runtime(五)
2019-03-29 本文已影响0人
dandelionYD
本文Demo代码见gitHubDemo
消息转发应用
myPerson.h
#import <Foundation/Foundation.h>
@interface myPerson : NSObject
- (void)run;
- (void)test;
- (void)other;
@end
myPerson.m
#import "myPerson.h"
@implementation myPerson
- (void)run{
NSLog(@"run-123");
}
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector{
// 本来能调用的方法
if ([self respondsToSelector:aSelector]) {
return [super methodSignatureForSelector:aSelector];
}
// 找不到的方法
return [NSMethodSignature signatureWithObjCTypes:"v@:"];
}
// 找不到的方法,都会来到这里
- (void)forwardInvocation:(NSInvocation *)anInvocation{
NSLog(@"找不到%@方法", NSStringFromSelector(anInvocation.selector));
}
@end
【main】
#import <Foundation/Foundation.h>
#import "myPerson.h"
int main(int argc, const char * argv[]) {
@autoreleasepool {
myPerson *p = [[myPerson alloc]init];
[p run];
[p test];
[p other];
}
return 0;
}
打印:
14.消息转发应用[26463:15281230] run-123
14.消息转发应用[26463:15281230] 找不到test方法
14.消息转发应用[26463:15281230] 找不到other方法
接下来我们看看Runtime的具体的使用
- 类
myPerson.h
#import <Foundation/Foundation.h>
@interface myPerson : NSObject
-(void)eat;
@end
myPerson.m
#import "myPerson.h"
@implementation myPerson
-(void)eat{
NSLog(@"%s",__FUNCTION__);
}
@end
myDog.h
#import <Foundation/Foundation.h>
@interface myDog : NSObject
-(void)eat;
@end
myDog.m
#import "myDog.h"
@implementation myDog
-(void)eat{
NSLog(@"%s",__FUNCTION__);
}
@end
#import <Foundation/Foundation.h>
#import <objc/runtime.h>
#import "myPerson.h"
#import "myDog.h"
void run(){
printf("run----\n");
}
int main(int argc, const char * argv[]) {
@autoreleasepool {
myPerson *p = [[myPerson alloc]init];
[p eat];
object_setClass(p,[myDog class]);//修改了isa指向
[p eat]; //调用了myDog里面的run方法
//object_isClass 判断一个OC对象是否为Class
NSLog(@"%d %d %d",
object_isClass(p),
object_isClass([myPerson class]),
object_isClass(object_getClass([myPerson class]))
);
NSLog(@"==========动态创建类=============");
// 创建类
Class newClass = objc_allocateClassPair([NSObject class], "myCat", 0);
class_addIvar(newClass, "_age", 4, 1, @encode(int));
class_addIvar(newClass, "_weight", 4, 1, @encode(int));
class_addMethod(newClass, @selector(run), (IMP)run, "v@:");
// 注册类
objc_registerClassPair(newClass);
id cat = [[newClass alloc] init];
[cat setValue:@10 forKey:@"_age"];
[cat setValue:@20 forKey:@"_weight"];
[cat run];
NSLog(@"%@ %@", [cat valueForKey:@"_age"], [cat valueForKey:@"_weight"]);
// 在不需要这个类时释放
objc_disposeClassPair(newClass);
}
return 0;
}
打印:
15.runtime的使用-类[32416:15549185] -[myPerson eat]
15.runtime的使用-类[32416:15549185] -[myDog eat]
15.runtime的使用-类[32416:15549185] 0 1 1
15.runtime的使用-类[32416:15549185] ==========动态创建类=============
run----
15.runtime的使用-类[32416:15549185] 10 20
- 成员变量和属性
myPerson.h
#import <Foundation/Foundation.h>
@interface myPerson : NSObject
@end
myPerson.m
#import "myPerson.h"
@implementation myPerson{
int _age;
NSString *_name;
float _height;
}
@end
【main.m】
#import <Foundation/Foundation.h>
#import <objc/runtime.h>
#import "myPerson.h"
int main(int argc, const char * argv[]) {
@autoreleasepool {
// 获取成员变量信息 和 设置
Ivar ageIvar = class_getInstanceVariable([myPerson class], "_age");
Ivar nameIvar = class_getInstanceVariable([myPerson class], "_name");
Ivar heightIvar = class_getInstanceVariable([myPerson class], "_height");
NSLog(@"%s %s", ivar_getName(ageIvar), ivar_getTypeEncoding(ageIvar));
NSLog(@"%s %s", ivar_getName(nameIvar), ivar_getTypeEncoding(nameIvar));
NSLog(@"%s %s", ivar_getName(heightIvar), ivar_getTypeEncoding(heightIvar));
myPerson *p = [[myPerson alloc] init];
/*
object_setIvar(p, nameIvar, @"123");
object_setIvar(p, ageIvar, (__bridge id)(void *)10);
object_setIvar(p, heightIvar,(__bridge id)(void *)180);
*/
//坑 object_getIvar 不支持非对象 https://www.jianshu.com/p/e498142f788d
//解决:
object_setIvar(p, nameIvar, @"123");
object_setIvar(p, ageIvar, @(10));
object_setIvar(p, heightIvar,@(180));
NSLog(@"name = %@", object_getIvar(p, nameIvar));
NSLog(@"age = %@", object_getIvar(p, ageIvar));
NSLog(@"height = %@", object_getIvar(p, heightIvar));
NSLog(@"====成员变量的数量====");
// 成员变量的数量
unsigned int count;
Ivar *ivars = class_copyIvarList([myPerson class], &count);
for (unsigned int i = 0; i<count; i++) {
// 取出i位置的成员变量
Ivar ivar = ivars[I];
NSLog(@"%s %s", ivar_getName(ivar), ivar_getTypeEncoding(ivar));
}
free(ivars);
}
return 0;
}
打印:
16.runtime的使用-成员变量和属性[35903:15840080] _age I
16.runtime的使用-成员变量和属性[35903:15840080] _name @"NSString"
16.runtime的使用-成员变量和属性[35903:15840080] _height f
16.runtime的使用-成员变量和属性[35903:15840080] name = 123
16.runtime的使用-成员变量和属性[35903:15840080] age = 10
16.runtime的使用-成员变量和属性[35903:15840080] height = 180
16.runtime的使用-成员变量和属性[35903:15840080] ====成员变量的数量====
16.runtime的使用-成员变量和属性[35903:15840080] _age I
16.runtime的使用-成员变量和属性[35903:15840080] _name @"NSString"
16.runtime的使用-成员变量和属性[35903:15840080] _height f
项目实践:
// unsigned int count;
// Ivar *ivars = class_copyIvarList([UITextField class], &count);
// for (int i = 0; i < count; i++) {
// // 取出i位置的成员变量
// Ivar ivar = ivars[I];
// NSLog(@"%s %s", ivar_getName(ivar), ivar_getTypeEncoding(ivar));
// }
// free(ivars);
self.textField.placeholder = @"请输入用户名";
[self.textField setValue:[UIColor redColor] forKeyPath:@"_placeholderLabel.textColor"];
<===>
// UILabel *placeholderLabel = [self.textField valueForKeyPath:@"_placeholderLabel"];
// placeholderLabel.textColor = [UIColor redColor];
<===>
// NSMutableDictionary *attrs = [NSMutableDictionary dictionary];
// attrs[NSForegroundColorAttributeName] = [UIColor redColor];
// self.textField.attributedPlaceholder = [[NSMutableAttributedString alloc] initWithString:@"请输入用户名" attributes:attrs];
字典转模型
myPerson.h
#import <Foundation/Foundation.h>
@interface myPerson : NSObject
@property(nonatomic,assign)int ID;
@property(nonatomic,assign)double height;
@property(nonatomic,assign)double weight;
@property(nonatomic,strong)NSString *name;
@end
myPerson.m
#import "myPerson.h"
@implementation myPerson
@end
NSObject+json.h
#import <Foundation/Foundation.h>
@interface NSObject (json)
+ (instancetype)my_objectWithJson:(NSDictionary *)json;
@end
NSObject+json.m
#import "NSObject+json.h"
#import <objc/runtime.h>
@implementation NSObject (json)
+ (instancetype)my_objectWithJson:(NSDictionary *)json{
id obj = [[self alloc] init];
unsigned int count;
Ivar *ivars = class_copyIvarList(self, &count);
for (unsigned int i = 0; i < count; i++) {
// 取出i位置的成员变量
Ivar ivar = ivars[I];
NSMutableString *name = [NSMutableString stringWithUTF8String:ivar_getName(ivar)];
[name deleteCharactersInRange:NSMakeRange(0, 1)];
// 设值
id value = json[name];
if ([name isEqualToString:@"ID"]){
value = json[@"id"];
}
[obj setValue:value forKey:name];
}
free(ivars);
return obj;
}
@end
【main】
#import <Foundation/Foundation.h>
#import "NSObject+json.h"
#import "myPerson.h"
int main(int argc, const char * argv[]) {
@autoreleasepool {
// 字典转模型
NSDictionary *json = @{
@"id" : @20,
@"height" : @20,
@"weight" : @60,
@"name" : @"Jack"
};
myPerson *person = [myPerson my_objectWithJson:json];
NSLog(@"id=>%d height=>%f weight=>%f name=>%@",person.ID,person.height,person.weight,person.name);
}
return 0;
}
打印:
17.runtime的使用-字典转模型[36043:15855031] id=>20 height=>20.000000 weight=>60.000000 name=>Jack
-
方法
runtime_18.png
交换方法
myPerson.h
#import <Foundation/Foundation.h>
@interface myPerson : NSObject
-(void)run;
-(void)walk;
@end
myPerson.m
#import "myPerson.h"
@implementation myPerson
-(void)run{
NSLog(@"%s",__FUNCTION__);
}
-(void)walk{
NSLog(@"%s",__FUNCTION__);
}
@end
【main】
#import <Foundation/Foundation.h>
#import "myPerson.h"
#import <objc/runtime.h>
int main(int argc, const char * argv[]) {
@autoreleasepool {
myPerson *p = [[myPerson alloc]init];
Method runMethod = class_getInstanceMethod([myPerson class], @selector(run));
Method walkMethod = class_getInstanceMethod([myPerson class], @selector(walk));
method_exchangeImplementations(runMethod, walkMethod);
[p run];
//替换方法
class_replaceMethod(
[myPerson class],
@selector(walk),
imp_implementationWithBlock(^{
NSLog(@"block实现方法的实现啦");
}), "v@:");
[p walk];
}
return 0;
}
打印:
18.runtime的使用--交换IMP[36122:15870626] -[myPerson walk]
18.runtime的使用--交换IMP[36173:15876293] block实现方法的实现啦
补充:
类名 | 真身 |
---|---|
NSArray | __NSArrayI |
NSMutableArray | __NSArrayM |
NSDictionary | __NSDictionaryI |
NSMutableDictionary | __NSDictionaryM |
示例
1.拦截UIButton的点击事件
UI
#import <UIKit/UIKit.h>
@interface UIControl (Extension)
@end
UIControl+Extension.m
#import "UIControl+Extension.h"
#import <objc/runtime.h>
@implementation UIControl (Extension)
+ (void)load{
// hook:钩子函数
Method method1 = class_getInstanceMethod(self, @selector(sendAction:to:forEvent:));
Method method2 = class_getInstanceMethod(self, @selector(my_sendAction:to:forEvent:));
method_exchangeImplementations(method1, method2);
}
- (void)my_sendAction:(SEL)action to:(id)target forEvent:(UIEvent *)event{
NSLog(@"%@-%@-%@", self, target, NSStringFromSelector(action));
// 调用系统原来的实现
[self my_sendAction:action to:target forEvent:event];
// if ([self isKindOfClass:[UIButton class]]) {
// // 拦截了所有按钮的事件
//
// }
}
@end
2.NSMutableArray 添加nil判别
NSMutableArray+Extension.h
#import <Foundation/Foundation.h>
@interface NSMutableArray (Extension)
@end
NSMutableArray+Extension.m
#import "NSMutableArray+Extension.h"
#import <objc/runtime.h>
@implementation NSMutableArray (Extension)
+ (void)load{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
// 类簇:NSString、NSArray、NSDictionary,真实类型是其他类型
Class cls = NSClassFromString(@"__NSArrayM");
Method method1 = class_getInstanceMethod(cls, @selector(insertObject:atIndex:));
Method method2 = class_getInstanceMethod(cls, @selector(my_insertObject:atIndex:));
method_exchangeImplementations(method1, method2);
});
}
- (void)my_insertObject:(id)anObject atIndex:(NSUInteger)index{
if (anObject == nil) return;
[self my_insertObject:anObject atIndex:index];
}
@end
3.拦截NSDictionary
NSMutableDictionary+Extension.h
#import <Foundation/Foundation.h>
@interface NSMutableDictionary (Extension)
@end
NSMutableDictionary+Extension.m
#import "NSMutableDictionary+Extension.h"
#import <objc/runtime.h>
@implementation NSMutableDictionary (Extension)
+ (void)load{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
Class cls = NSClassFromString(@"__NSDictionaryM");
unsigned int count;
Method *methodList = class_copyMethodList(cls, &count);
for (unsigned int i = 0; i < count; i++) {
Method method = methodList[I];
NSString *methodName = NSStringFromSelector(method_getName(method));
NSLog(@"方法名:%d----%@",i,methodName);
}
free(methodList);
Method method1 = class_getInstanceMethod(cls, @selector(setObject:forKey:));
Method method2 = class_getInstanceMethod(cls, @selector(my_setObject:forKey:));
method_exchangeImplementations(method1, method2);
Class cls2 = NSClassFromString(@"__NSDictionaryI");
Method method3 = class_getInstanceMethod(cls2, @selector(objectForKeyedSubscript:));
Method method4 = class_getInstanceMethod(cls2, @selector(my_objectForKeyedSubscript:));
method_exchangeImplementations(method3, method4);
});
}
- (void)my_setObject:(id)obj forKey:(id<NSCopying>)key{
if (!obj) return;
if (!key) return;
[self my_setObject:obj forKey:key];
}
- (id)my_objectForKeyedSubscript:(id)key{//dict[nil]
if (!key) return nil;
return [self my_objectForKeyedSubscript:key];
}
@end
友情链接: