Objective-C做爲一種動態消息型語言,其機制不一樣於Java,C#等編譯型語言.
它將數據類型的肯定等工做推遲到了運行時期來執行,而且它調用方法的方式實質是像對象發送消息,根據selector在對象的本類以及父類中的方法列表進行查找,若是都找不到就會啓動消息轉發機制.atom
回到正題,這個話題我想談下OC的單繼承原則.
OC確實是只能單繼承的語言,可是基於運行時的機制,卻有一種方法讓它來實現一下"僞多繼承".就是利用NSProxy這個類.spa
NSProxy是和NSObject同級的一個類,能夠說它是一個虛擬類,它只是實現了<NSObject>的協議.它的做用有點相似於一個複製類,有人曾經笑談它是複製操做,想一想其實也挺貼切的,其實原理確實如此.code
工做原理:
用一個繼承於NSProxy的子類,在它內部實現一些方法,暴露一個公開方法transform,這個方法是使它變身的關鍵.而後它變身以後能夠對那些對象發送消息,而且能夠在內部攔截消息的內容並修改.
能夠說,NSProxy幾乎能夠變身成爲任何對象.orm
//JanProxy.h #import <Foundation/Foundation.h> @interface JanProxy : NSProxy - (void)transformObjc:(NSObject *)objc; @end
//JanProxy.m #import "JanProxy.h" @interface JanProxy () @property(nonatomic,strong)NSObject *objc; @end @implementation JanProxy - (void)transformObjc:(NSObject *)objc { //複製對象 self.objc = objc; } //2.有了方法簽名以後就會調用方法實現 - (void)forwardInvocation:(NSInvocation *)invocation { if (self.objc) { //攔截方法的執行者爲複製的對象 [invocation setTarget:self.objc]; if ([self.objc isKindOfClass:[NSClassFromString(@"Cat") class]]) { //攔截參數 Argument:表示的是方法的參數 index:表示的是方法參數的下標 NSString *str = @"攔截消息"; [invocation setArgument:&str atIndex:2]; } //開始調用方法 [invocation invoke]; } } //1.查詢該方法的方法簽名 - (NSMethodSignature *)methodSignatureForSelector:(SEL)sel { NSMethodSignature *signature = nil; if ([self.objc methodSignatureForSelector:sel]) { signature = [self.objc methodSignatureForSelector:sel]; } else { signature = [super methodSignatureForSelector:sel]; } return signature; } @end
使用方法對象
Dog *dog = [[Dog alloc]init]; //OC中方法的調用本質上是給這個對象發送一個消息 Cat *cat = [[Cat alloc] init]; //開始複製攔截方法 JanProxy *proxy = [JanProxy alloc]; //開始變身成貓 [proxy transformObjc:cat]; //開始調貓的方法 [proxy performSelector:@selector(eat:) withObject:@"貓發出消息"]; //開始變身成狗 [proxy transformObjc:Dog]; //開始調用學生的方法 [proxy performSelector:@selector(shut)];
最後的結果繼承
發現沒有,貓發出消息已經被子類的內部攔截而且作出了修改.rem
OC中存在這麼一個默默無聞的類NSProxy,填補了"多繼承"這個空白區.get