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.lxweimin.com/p/e4f1fb537af9)(runtime添加屬性)
描述:用戶正常操作情況下,單次點擊,button只響應一次點擊,但如果多次點擊,會引起事件被多次執行,導致一些bug的出現。
方法:runtime動態的給UIButton這個類添加兩個屬性`x_acceptEventInterval`&`x_ignoreEvent`,在控制器中控制button的 `x_acceptEventInterval`&`x_ignoreEvent` 屬性的值來解決UIButton的多次點擊