學了那么久的Objective-C,給我的感覺就是它什么都是動態(tài)的撵割,你將會聽到一個新的名詞:
一、動態(tài)方法解析
-
1包颁、+(BOOL) resolveInstanceMethod:(SEL) sel
這是NSObject根類提供的類方法瞻想,調用時機為當被調用的方法實現部分沒有找到,而消息轉發(fā)機制啟動之前的這個中間時刻娩嚼。
Objective-C2.0 提供了@dynamic關鍵字。這個關鍵字有兩個作用:
①告訴編譯器不要創(chuàng)建實現屬性所用的實例變量岳悟;
②告訴編譯器不要創(chuàng)建該屬性的get和setter方法佃迄。
如果我們在@interface接口文件中聲明了一個屬性,如下所示:
@property(nonatomic,retain) NSString *name;
默認情況下贵少,編譯器會為當前類自動生成一個NSString *_name的實例變量(如果想改變實例變量的名稱可以用@synthesize關鍵字)呵俏,同時會生成兩個名為- (NSString *)name和- (void)setName:(NSString *)aName的存取方法。
而@dynamic關鍵字就是告訴編譯器不要做這些事滔灶,同時在使用了存取方法時也不要報錯普碎,即讓編譯器相信存取方法會在運行時找到。
比如在@implementation文件中做了如下聲明:
@dynamic name;
如果使用了name屬性的setter方法录平,又不想在運行時崩潰麻车,就可以在運行時做點動作:
void dynamicMethodIMP(id self, SEL _cmd)
{
// implementation ....
}
+ (BOOL)resolveInstanceMethod:(SEL)sel
{
NSLog(@"sel is %@", NSStringFromSelector(sel));
if(sel == @selector(setName:)){
class_addMethod([self class],sel,(IMP)dynamicMethodIMP,"v@:");
return YES;
}
return [super resolveInstanceMethod:sel];
}
在resolveInstanceMethod的實現中,我們通過class_addMethod方法動態(tài)的向當前對象增加了dynamicMethodIMP函數斗这,來代替-(void)setName:(NSString *)name的實現部分动猬,從而達到了動態(tài)生成name屬性方法的目的。
值得說明的是:
①在上個例子中涝影,我們自己實現了-(void)setName:(NSString *)name方法枣察,則在運行的時候争占,調用完我們實現的-(void)setName:(NSString *)name方法后燃逻,運行時系統仍然會調+(BOOL) resolveInstanceMethod:(SEL) sel方法,只不過這里的sel會變成_doZombieMe臂痕,從而我們實現重定向的if分支就進不去了伯襟,即我們實現的方法不會被覆蓋。
②"v@:"屬于Objective-C類型編碼的內容握童,感興趣的同學可以自己google一下姆怪。
二、runtime system消息轉發(fā)機制
對象是謙恭的澡绩,它會接收所有發(fā)送過來的消息稽揭,哪怕這些消息自己無法響應。問題來了:當對象無法響應這些消息時怎么辦肥卡?runtime提供了消息轉發(fā)機制來處理該問題溪掀。
當外部調用的某個方法對象沒有實現,而且resolveInstanceMethod方法中也沒有做重定向處理時步鉴,就會觸發(fā)- (void)forwardInvocation:(NSInvocation *)anInvocation方法揪胃。在該方法中璃哟,可以實現對不能處理的消息做的一些默認處理,也可以以其它的某種方式來避免錯誤被拋出。像forwardInvocation:的名字一樣,這個方法通常用來將不能處理的消息轉發(fā)給其它的對象喊递。通常我們重寫該方法的方式如下所示:
-(void)forwardInvocation:(NSInvocation *)invocation
{
SEL invSEL = invocation.selector;
if ([someOtherObject respondsToSelector:invSEL])
[anInvocation invokeWithTarget:someOtherObject];
} else {
[self doesNotRecognizeSelector:invSEL];
}
}
怎么看著有點像多繼承呀随闪??骚勘?你說對了铐伴,消息轉發(fā)提供了多重繼承的很多特性。然而,兩者有很大的不同:多重繼承是將不同的行為封裝到單個的對象中,有可能導致龐大的,復雜的對象俏讹。而消息轉發(fā)是將問題分解到更小的對象中,但是又以一種對消息發(fā)送對象來說完全透明的方式將這些對象聯系起來盛杰。總之藐石,Objective-C通過這種方式即供,一定程度上減小了自己不支持多繼承的劣勢。