iOS底層原理runtime 方法列表 以及常用api調用
objc_系列函數關注于宏觀使用,如類與協議的空間分配,注冊,注銷等操作
class_系列函數關注于類的內部,如實例變量,屬性,方法,協議等相關問題
objcet_系列函數關注于對象的角度,如實例變量
method_系列函數關注于方法內部,如果方法的參數及返回值類型和方法的實現
property_系類函數關注與屬性*內部,如屬性的特性等
protocol_系類函數關注與協議相關
ivar_xxx函數關注與實例變量的東西
sel_xxx主要討論關于方法編號相關的東西
imp_xxx主要討論關于方法實現相關的
下面我們來玩一下這些常用的api
//交換方法
Method m1 = class_getInstanceMethod(self, @selector(viewWillAppear:));
Method m2 = class_getInstanceMethod(self, @selector(tz_viewWillAppear:));
method_exchangeImplementations(m1, m2);
// 關聯屬性
- (void)setViewColor:(NSString *)viewColor{
objc_setAssociatedObject(self, &associatedObjectKey, @"addProperty", OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (NSString *)viewColor{
return objc_getAssociatedObject(self, &associatedObjectKey);
}
/// 創建一類對
Class TZCat = objc_allocateClassPair([NSObject class], "TZCat", 0);
/// 添加實例變量
// const char* types= "v@:"
NSString* name = @"name";
class_addIvar(TZCat, name.UTF8String, sizeof(id), log2(sizeof(id)), @encode(id));
// 添加方法
class_addMethod(TZCat, @selector(hunting), (IMP)hunting, "v@:");
/// 注冊類
objc_registerClassPair(TZCat);
// 創建實例對象
id cat = [[TZCat alloc] init];
[cat setValue:@"Tom" forKey:@"name"];
NSLog(@"name = %@", [cat valueForKey:name]);
/// 方法調用
[cat performSelector:@selector(hunting)];
// 獲取成員變量列表
unsigned int count = 0;
Ivar* ivars = class_copyIvarList([self class], &count);
for (int i = 0; i < count; i++) {
Ivar var = ivars[i];
const char* name = ivar_getName(var);
NSString* key = [NSString stringWithUTF8String:name];
id value = [self valueForKey:key];
[aCoder encodeObject:value forKey:key];
}
free(ivars);
消息轉發機制
/*
* 第一步 實例方法專用 方法解析
**/
+ (BOOL)resolveInstanceMethod:(SEL)sel{
NSLog(@"%@",NSStringFromSelector(sel));
if(sel == @selector(DoThings:Num:)){
class_addMethod([self class], sel, (IMP)MyMethodIMP, "v@:");
return YES;
}
return [super resolveInstanceMethod:sel];
}
/*
* 第二步 如果第一步未處理,那么讓別的對象去處理這個方法
**/
-(id)forwardingTargetForSelector:(SEL)aSelector{
if([NSStringFromSelector(aSelector) isEqualToString:@"DoThings:Num:"]){
return [[Tools alloc]init];
}
return [super forwardingTargetForSelector:aSelector];
}
/*
* 第三步 如果前兩步未處理,這是最后處理的機會將目標函數以其他形式執行
**/
-(NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector{
NSString *SelStr = NSStringFromSelector(aSelector);
if([SelStr isEqualToString:@"DoThings:Num:"]){
[NSMethodSignature signatureWithObjCTypes:"v@:"];
}
return [super methodSignatureForSelector:aSelector];
}
-(void)forwardInvocation:(NSInvocation *)anInvocation{
//改變消息接受者對象
[anInvocation invokeWithTarget:[[Tools alloc]init]];
//改變消息的SEL
anInvocation.selector = @selector(flyGame);
[anInvocation invokeWithTarget:self];
}
- (void)flyGame{
NSLog(@"我要飛翔追逐夢想!");
}
/*
* 作為找不到函數實現的最后一步,NSObject實現這個函數只有一個功能,就是拋出異常。
* 雖然理論上可以重載這個函數實現保證不拋出異常(不調用super實現),但是蘋果文檔著重提出“一定不能讓這個函數就這么結束掉,必須拋出異常”。
*
***/
- (void)doesNotRecognizeSelector:(SEL)aSelector{
}
消息機制
objc_msgSend("對象","SEL","參數"...)
objc_msgSend( id self, SEL op, ... )
runtime 源碼地址:https://github.com/gongkuihua/objc4-750-master