iOS runtime 知识点整理

Posted 小C酱

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了iOS runtime 知识点整理相关的知识,希望对你有一定的参考价值。

// ------ 动态创建类, 添加成员变量, 赋值并调用动态添加的方法 -------

 1 @implementation ViewController
 2 
 3 - (void)viewDidLoad {
 4     [super viewDidLoad];
 5     
 6     // 动态创建People类, 继承自NSObject类
 7     // 额外空间     未知,通常设置为 0
 8     Class People = objc_allocateClassPair([NSObject class], "Person", 0);
 9     
10     // 以NSString*为例
11     // 变量size sizeof(NSString)
12     // 对齐     指针类型的为log2(sizeof(NSString*))
13     // 类型     @encode(NSString*)
14     // 添加_name 成员变量
15     BOOL flag1 = class_addIvar([People class], "_name", sizeof(NSString *), log2(sizeof(NSString *)), @encode(NSString *));
16     if (flag1) {
17         NSLog(@"添加成员变量_name成功!");
18     }
19     // 添加_age 成员变量
20     BOOL flag2 = class_addIvar([People class], "_age", sizeof(int), sizeof(int), @encode(int));
21     if (flag2) {
22         NSLog(@"添加成员变量_age成功!");
23     }
24     
25     // 注册方法名为say:的方法
26     SEL s = sel_registerName("say:");
27     
28     // 添加say:方法的实现
29     // "[email protected]:@"
30     // v表示返回值为void, i表示返回值为int
31     // @表示参数id(self)
32     // :表示SEL(_cmd)
33     // @表示id
34     class_addMethod([People class], s, (IMP)sayFunction1, "[email protected]:@");
35     
36     // 注册该类
37     objc_registerClassPair([People class]);
38     
39     // 创建类的实例
40     id peopleInstance = [[People alloc] init];
41     
42     // KVC 动态改变 对象peopleInstance 中的实例变量
43     [peopleInstance setValue:@"老师" forKey:@"name"];
44     //    Ivar nameVar = class_getInstanceVariable([People class], "_name");
45     //    object_setIvar(peopleInstance, nameVar, @"老师");
46     
47     // 从类中获取成员变量Ivar
48     Ivar ageIvar = class_getInstanceVariable([People class], "_age");
49     // 为成员变量赋值
50     object_setIvar(peopleInstance, ageIvar, @33);
51     
52     // 调用 peopleInstance 对象中的 s 方法选择器对应的方法
53     //    objc_msgSend(peopleInstance, s, @"大家好!");
54     ((void (*)(id, SEL, id))objc_msgSend)(peopleInstance, s, @"大家好!!!");
55     
56     // 当People类或者它的子类的实例还存在,则不能调用objc_disposeClassPair这个方法;因此这里要先销毁实例对象后才能销毁类;
57     peopleInstance = nil;
58     
59     // 销毁类
60     objc_disposeClassPair([People class]);
61 }
62 
63 // 动态添加方法的实现
64 void sayFunction1(id self, SEL _cmd, id some) {
65     Ivar ageIvar = class_getInstanceVariable([self class], "_age");
66     NSString *age = object_getIvar(self, ageIvar);
67     NSLog(@"%@岁的%@说: %@, %@", age,[self valueForKey:@"name"],some, NSStringFromSelector(_cmd));
68 }


// ------ 获取属性, 成员变量 以及 方法 -------

 1 @implementation People
 2 
 3 - (NSDictionary *)allProperties {
 4     unsigned int count = 0;
 5     
 6     // 获取类的所有属性, 如果没有属性count就为0
 7     objc_property_t *properties = class_copyPropertyList([self class], &count);
 8     NSMutableDictionary *resultDict = [@{} mutableCopy];
 9     
10     for (int i = 0; i < count; i++) {
11         // 获取属性的名称和值
12         const char *propertyName = property_getName(properties[i]);
13         NSString *name = [NSString stringWithUTF8String:propertyName];
14         id propertyValue = [self valueForKey:name];
15         
16         if (propertyValue) {
17             resultDict[name] = propertyValue;
18         } else {
19             resultDict[name] = @"字典的key对应的value不能为nil哦!";
20         }
21     }
22     
23     // 这里properties是一个数组指针, 我们需要使用free函数来释放内存
24     free(properties);
25     
26     return resultDict;
27 }
28 
29 - (NSDictionary *)allIvars {
30     unsigned int count = 0;
31     NSMutableDictionary *resultDict = [@{} mutableCopy];
32     
33     // 获取类的所有成员变量ivar
34     Ivar *ivars = class_copyIvarList([self class], &count);
35     
36     for (int i = 0; i < count; i++) {
37         const char *ivarName = ivar_getName(ivars[i]);
38         NSString *name = [NSString stringWithUTF8String:ivarName];
39         id ivarValue = [self valueForKey:name];
40         
41         if (ivarValue) {
42             resultDict[name] = ivarValue;
43         } else {
44             resultDict[name] = @"字典的key对应的value不能为nil哦~";
45         }
46     }
47     
48     free(ivars);
49     
50     return resultDict;
51 }
52 
53 - (NSDictionary *)allMethods {
54     unsigned int count = 0;
55     NSMutableDictionary *resultDict = [@{} mutableCopy];
56     
57     Method *methods = class_copyMethodList([self class], &count);
58     
59     for (int i = 0; i < count; i++) {
60         SEL methodSEL = method_getName(methods[i]);
61         const char *methodName = sel_getName(methodSEL);
62         NSString *name = [NSString stringWithUTF8String:methodName];
63         
64         unsigned int arguments = method_getNumberOfArguments(methods[i]);
65         
66         resultDict[name] = @(arguments - 2);
67     }
68     
69     free(methods);
70     
71     return resultDict;
72 }
73 
74 @end

 

// ------- 给类添加 属性 及 回调block -------

 1 // 在People的分类中进行
 2 
 3 typedef void(^CodingCallBack)();
 4 
 5 @interface People (Associated)
 6 
 7 @property (strong, nonatomic) NSNumber *associatedBust; // 胸围
 8 @property (copy, nonatomic) CodingCallBack associatedCallBack; // 写代码
 9 
10 @end
11 
12 
13 @implementation People (Associated)
14 
15 - (NSNumber *)associatedBust {
16     // 获取关联对象
17     return objc_getAssociatedObject(self, @selector(associatedBust));
18 }
19 
20 - (void)setAssociatedBust:(NSNumber *)associatedBust {
21     // 设置关联对象
22     objc_setAssociatedObject(self, @selector(associatedBust), associatedBust, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
23 }
24 
25 - (CodingCallBack)associatedCallBack {
26     return objc_getAssociatedObject(self, @selector(associatedCallBack));
27 }
28 
29 - (void)setAssociatedCallBack:(CodingCallBack)associatedCallBack {
30     objc_setAssociatedObject(self, @selector(associatedCallBack), associatedCallBack, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
31 }
32 
33 @end

 

// ------- 序列化 及 反序列化 -------

 1 @interface People2 : NSObject <NSCoding>
 2 
 3 @property (nonatomic, copy) NSString *name; // 姓名
 4 @property (nonatomic, strong) NSNumber *age; // 年龄
 5 @property (nonatomic, copy) NSString *occupation; // 职业
 6 @property (nonatomic, copy) NSString *nationality; // 国籍
 7 
 8 @end
 9 
10 @implementation People2
11 
12 // 反序列化数据
13 - (instancetype)initWithCoder:(NSCoder *)coder
14 {
15     self = [super init];
16     if (self) {
17         unsigned int count = 0;
18         Ivar *ivars = class_copyIvarList([self class], &count);
19         
20         for (int i = 0; i < count; i++) {
21             const char *ivarName = ivar_getName(ivars[i]);
22             NSString *name = [NSString stringWithUTF8String:ivarName];
23             id value = [coder decodeObjectForKey:name];
24             
25             [self setValue:value forKey:name];
26         }
27         
28         free(ivars);
29     }
30     return self;
31 }
32 
33 // 序列化数据
34 - (void)encodeWithCoder:(NSCoder *)aCoder {
35     unsigned int count = 0;
36     Ivar *ivars = class_copyIvarList([self class], &count);
37     
38     for (int i = 0; i < count; i++) {
39         const char *ivarName = ivar_getName(ivars[i]);
40         NSString *name = [NSString stringWithUTF8String:ivarName];
41         id ivarValue = [self valueForKey:name];
42         
43         [aCoder encodeObject:ivarValue forKey:name];
44     }
45     
46     free(ivars);
47 }
48 
49 @end

 

// ------- Json 及 model 互转 -------

 1 @interface People2 : NSObject
 2 
 3 @property (nonatomic, copy) NSString *name; // 姓名
 4 @property (nonatomic, strong) NSNumber *age; // 年龄
 5 @property (nonatomic, copy) NSString *occupation; // 职业
 6 @property (nonatomic, copy) NSString *nationality; // 国籍
 7 
 8 // 生成model
 9 - (instancetype)initWithDictionary:(NSDictionary *)dictionary;
10 
11 // 转换成字典
12 - (NSDictionary *)covertToDictionary;
13 
14 @end
15 
16 @implementation People2
17 
18 - (instancetype)initWithDictionary:(NSDictionary *)dictionary {
19     self = [super init];
20     if (self) {
21         for (NSString *key in dictionary.allKeys) {
22             id value = dictionary[key];
23             
24             SEL setter = [self propertySetterByKey:key];
25             if (setter) {
26                 //                objc_msgSend(self, setter, value);
27                 ((void(*)(id, SEL, id))objc_msgSend)(self, setter, value);
28             }
29         }
30     }
31     return self;
32 }
33 
34 - (NSDictionary *)covertToDictionary {
35     unsigned int count = 0;
36     objc_property_t *properties = class_copyPropertyList([self class], &count);
37     
38     if (count != 0) {
39         NSMutableDictionary *resultDict = [@{} mutableCopy];
40         
41         for (int i = 0; i < count; i++) {
42             const char *propertyName = property_getName(properties[i]);
43             NSString *key = [NSString stringWithUTF8String:propertyName];
44             
45             SEL getter = [self propertyGetterByKey:key];
46             if (getter) {
47                 id value = ((id (*)(id, SEL))objc_msgSend)(self, getter);
48                 if (value) {
49                     resultDict[key] = value;
50                 } else {
51                     resultDict[key] = @"字典的key对应的value不能为nil哦!";
52                 }
53             }
54         }
55         
56         free(properties);
57         return resultDict;
58     }
59     
60     free(properties);
61     return nil;
62 }
63 
64 // --------- private method --------------------------------------
65 - (SEL)propertySetterByKey:(NSString *)key {
66     // set方法, 首字母大写
67     NSString *propertySetterName = [NSString stringWithFormat:@"set%@:", key.capitalizedString];
68     
69     SEL setter = NSSelectorFromString(propertySetterName);
70     if ([self respondsToSelector:setter]) {
71         return setter;
72     }
73     return nil;
74 }
75 
76 - (SEL)propertyGetterByKey:(NSString *)key {
77     SEL getter = NSSelectorFromString(key);
78     if ([self respondsToSelector:getter]) {
79         return getter;
80     }
81     return nil;
82 }
83 
84 @end


// ------- 动态转换方法实现 --------

 1 // 添加了方法声明, 但是没有实现该方法
 2 @interface People : NSObject
 3 
 4 - (void)sing;
 5 
 6 @end
 7 
 8 @implementation People
 9 
10 + (BOOL)resolveInstanceMethod:(SEL)sel {
11     // 我们没有给People类声明sing方法, 这里我们动态添加方法
12     if ([NSStringFromSelector(sel) isEqualToString:@"sing"]) {
13         class_addMethod([self class], sel, (IMP)otherSing, "[email protected]:");
14         return YES;
15     }
16     return [super resolveClassMethod:sel];
17 }
18 
19 void otherSing(id self, SEL cmd) {
20     NSLog(@"%@ 唱歌啦~~",((People *)self).name);
21 }
22 
23 @end

 

// ------- 修改方法调用对象 --------

 1 // Bird 类中并没有名字为 sing 的方法, 这时可以在Bird类中 将对象修改成People
 2 @interface Bird : NSObject
 3 
 4 @property (copy, nonatomic) NSString *name;
 5 
 6 @end
 7 
 8 @implementation Bird
 9 
10 // 第一步:我们不动态添加方法,返回NO,进入第二步;
11 + (BOOL)resolveInstanceMethod:(SEL)sel {
12     return NO;
13 }
14 
15 // 第二部:我们不指定备选对象响应aSelector,进入第三步;
16 - (id)forwardingTargetForSelector:(SEL)aSelector {
17     return nil;
18 }
19 
20 // 第三步:返回方法选择器,然后进入第四部;
21 - (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
22     if ([NSStringFromSelector(aSelector) isEqualToString:@"sing"]) {
23         return [NSMethodSignature signatureWithObjCTypes:"[email protected]:"];
24     }
25     return [super methodSignatureForSelector:aSelector];
26 }
27 
28 // 第四部:这步我们修改调用对象
29 - (void)forwardInvocation:(NSInvocation *)anInvocation {
30 // 我们改变调用对象为People
31     People *p = [[People alloc] init];
32     p.name = @"t1";
33 
34     [p sing];
35 }
36 
37 @end

 

// ------- 修改调用的方法 -------

 1 @interface Bird : NSObject
 2 
 3 @property (copy, nonatomic) NSString *name;
 4 
 5 @end
 6 
 7 @implementation Bird
 8 
 9 // 第一步:我们不动态添加方法,返回NO,进入第二步;
10 + (BOOL)resolveInstanceMethod:(SEL)sel {
11     return NO;
12 }
13 
14 // 第二部:我们不指定备选对象响应aSelector,进入第三步;
15 - (id)forwardingTargetForSelector:(SEL)aSelector {
16     return nil;
17 }
18 
19 // 第三步:返回方法选择器,然后进入第四部;
20 - (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
21     if ([NSStringFromSelector(aSelector) isEqualToString:@"sing"]) {
22         return [NSMethodSignature signatureWithObjCTypes:"[email protected]:"];
23     }
24     return [super methodSignatureForSelector:aSelector];
25 }
26 
27 // 第四部:这步我们修改调用方法
28 - (void)forwardInvocation:(NSInvocation *)anInvocation {
29     [anInvocation setSelector:@selector(dance)];
30     // 还要指定是哪个对象的方法
31     [anInvocation invokeWithTarget:self];
32 }
33 
34 // 若forwardInvocation没有实现,则会调用此方法
35 - (void)doesNotRecognizeSelector:(SEL)aSelector {
36     NSLog(@"消息无法处理: %@", NSStringFromSelector(aSelector));
37 }
38 
39 - (void)dance {
40     NSLog(@"跳舞!! come on!~");
41 }
42 
43 @end


以上是关于iOS runtime 知识点整理的主要内容,如果未能解决你的问题,请参考以下文章

Runtime-iOS运行时基础篇

IOS开发-OC学习-常用功能代码片段整理

Cocoa Runtime系统知识整理

iOS:runtime最全的知识总结

Runtime知识点

iOS-『Runtime』详解基础知识