首页 > 代码库 > iOS runtime 知识点整理
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 // "v@:@" 30 // v表示返回值为void, i表示返回值为int 31 // @表示参数id(self) 32 // :表示SEL(_cmd) 33 // @表示id 34 class_addMethod([People class], s, (IMP)sayFunction1, "v@:@"); 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 =http://www.mamicode.com/ [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 =http://www.mamicode.com/ [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 =http://www.mamicode.com/ [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 =http://www.mamicode.com/ [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 =http://www.mamicode.com/ 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 = http://www.mamicode.com/((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, "v@:"); 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:"v@:"]; 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:"v@:"]; 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 知识点整理
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。