1. 概述
- 能动态产生一个类,一个成员变量,一个方法
- 能动态修改一个类,一个成员变量,一个方法
- 能动态删除一个类,一个成员变量,一个方法
2. runtime应用
- 获取列表:通过runtime的一系列方法动态的遍历一个类的所有成员变量,用于字典转模型,归档解档操作,获取类的一些信息(包括属性列表,方法列表,成员变量列表,和遵循的协议列表)。
#import <objc/runtime.h>
//获取属性列表
objc_property_t *propertyList = class_copyPropertyList([self class], &count);
//获取方法列表
Method *methodList = class_copyMethodList([self class], &count);
//获取成员变量列表
Ivar *ivarList = class_copyIvarList([self class], &count);
//获取协议列表
__unsafe_unretained Protocol **protocolList = class_copyProtocolList([self class], &count);
- 动态添加方法
+ (BOOL)resolveInstanceMethod:(SEL)sel{
//给本类动态添加一个方法
if ([NSStringFromSelector(sel) isEqualToString:@"resolveAdd:"]) {
class_addMethod(self, sel, (IMP)runAddMethod, "v@:*");
}
return YES;
}
- 关联对象:允许开发者对已经存在的类在 Category 中添加自定义的属性:
//首先定义一个全局变量,用它的地址作为关联对象的key
static char associatedObjectKey;
//设置关联对象
objc_setAssociatedObject(target, &associatedObjectKey, @"添加的字符串属性", OBJC_ASSOCIATION_RETAIN_NONATOMIC);
//获取关联对象
NSString *string = objc_getAssociatedObject(target, &associatedObjectKey);
NSLog(@"AssociatedObject = %@", string);
objc_removeAssociatedObjects
方法将会移除源对象中所有的关联对象.
-
方法交换:通过runtime的
method_exchangeImplementations(Method m1, Method m2)
方法,可以进行交换方法的实现;一般用自己写的方法(常用在自己写的框架中,添加某些防错措施)来替换系统的方法实现
#import "UIViewController+swizzling.h"
#import <objc/runtime.h>
@implementation UIViewController (swizzling)//load方法会在类第一次加载的时候被调用
//调用的时间比较靠前,适合在这个方法里做方法交换
+ (void)load{
//方法交换应该被保证,在程序中只会执行一次
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
//获得viewController的生命周期方法的
selector SEL systemSel = @selector(viewWillAppear:);
//自己实现的将要被交换的方法的
selector SEL swizzSel = @selector(swiz_viewWillAppear:);
//两个方法的Method
Method systemMethod = class_getInstanceMethod([self class], systemSel);
Method swizzMethod = class_getInstanceMethod([self class], swizzSel);
//首先动态添加方法,实现是被交换的方法,返回值表示添加成功还是失败
BOOL isAdd = class_addMethod(self, systemSel, method_getImplementation(swizzMethod), method_getTypeEncoding(swizzMethod));
if (isAdd) {
//如果成功,说明类中不存在这个方法的实现
//将被交换方法的实现替换到这个并不存在的实现
class_replaceMethod(self, swizzSel, method_getImplementation(systemMethod), method_getTypeEncoding(systemMethod));
}else{
//否则,交换两个方法的实现
method_exchangeImplementations(systemMethod, swizzMethod);
}
});
}
- (void)swiz_viewWillAppear:(BOOL)animated{
//这时候调用自己,看起来像是死循环
//但是其实自己的实现已经被替换了
[self swiz_viewWillAppear:animated];
NSLog(@"swizzle");
}
@end
在一个自己定义的viewController中重写viewWillAppear
- (void)viewWillAppear:(BOOL)animated{
[super viewWillAppear:animated];
NSLog(@"viewWillAppear");
}
【注】方法交换更像是实现AOP面向切面编程思想的最佳技术。既然是切面,就一定不要忘记,交换完再调回自己。一定要保证只交换一次,否则就会很乱。最后,据说这个技术很危险,谨慎使用。
字典与模型互转
(建议直接用MJExtension)-
自动归档
1.使用 class_copyIvarList 方法获取当前 Model 的所有成员变量.
2.使用 ivar_getName 方法获取成员变量的名称.
3.通过 KVC 来读取 Model 的属性值(encodeWithCoder:),以及给 Model 的属性赋值(initWithCoder:).#import "TestModel.h" #import <objc/runtime.h> #import <objc/message.h> @implementation TestModel - (void)encodeWithCoder:(NSCoder *)aCoder{ unsigned int outCount = 0; Ivar *vars = class_copyIvarList([self class], &outCount); for (int i = 0; i < outCount; i ++) { Ivar var = vars[i]; const char *name = ivar_getName(var); NSString *key = [NSString stringWithUTF8String:name]; // 注意kvc的特性是,如果能找到key这个属性的setter方法,则调用setter方法 // 如果找不到setter方法,则查找成员变量key或者成员变量_key,并且为其赋值 // 所以这里不需要再另外处理成员变量名称的“_”前缀 id value = [self valueForKey:key]; [aCoder encodeObject:value forKey:key]; }
}
- (nullable instancetype)initWithCoder:(NSCoder *)aDecoder{
if (self = [super init]) {
unsigned int outCount = 0;
Ivar *vars = class_copyIvarList([self class], &outCount);
for (int i = 0; i < outCount; i ++) {
Ivar var = vars[i];
const char *name = ivar_getName(var);
NSString *key = [NSString stringWithUTF8String:name];
id value = [aDecoder decodeObjectForKey:key];
[self setValue:value forKey:key];
}
}
return self;
}
@end
###3.举例说明
- [Runtime优雅的解决UIButton多次点击(重复点击)](http://www.jianshu.com/p/e4f1fb537af9)(runtime添加属性)
描述:用户正常操作情况下,单次点击,button只响应一次点击,但如果多次点击,会引起事件被多次执行,导致一些bug的出现。
方法:runtime动态的给UIButton这个类添加两个属性`x_acceptEventInterval`&`x_ignoreEvent`,在控制器中控制button的 `x_acceptEventInterval`&`x_ignoreEvent` 属性的值来解决UIButton的多次点击