是不是曾經在別人面前誇下海口:Objective-C
中所有的類的基類都是NSObject
;我之前也一直也這麼以為的,但是認真看了下官方文件:
啪啪,好響,好疼~(看來英文水平也很重要啊......)
不賣關子了,我們今天要討論的就是NSProxy
。它是跟NSObject
屬於同一級別的類,是個抽象類,只是實現了<NSObject>
的協議;
按照官方的定義:NSProxy
是一個為物件定義介面的抽象父類,並且為其它物件或者一些不存在的物件扮演了替身角色。通常,給proxy的訊息被轉發給實際物件或者導致proxy載入(轉化它為)實際物件。NSProxy
的子類能被用來實現透明的分散式訊息(例如:NSDistantObject)或者延緩要花費昂貴代價建立的物件的實現。
下面我們看看NSProxy
是怎麼複製別的類(幾乎所有類)的:
我們先建立一個類繼承自NSProxy
:
#import "KakashiProxy.h"
@interface KakashiProxy ()
@property(nonatomic,strong)NSObject *objc;
@end
@implementation KakashiProxy
- (void)changeObj:(NSObject *)obj {
self.objc = obj;
}
//方法簽名
- (NSMethodSignature *)methodSignatureForSelector:(SEL)sel {
NSMethodSignature *signature = nil;
if ([self.objc methodSignatureForSelector:sel]) {
signature = [self.objc methodSignatureForSelector:sel];
}else {
signature = [super methodSignatureForSelector:sel];
}
return signature;
}
//呼叫方法實現
- (void)forwardInvocation:(NSInvocation *)invocation {
if ([self.objc respondsToSelector:invocation.selector]) {
NSString *selName = NSStringFromSelector(invocation.selector);
NSLog(@"selector name : %@",selName);
//這裡我們可以做一些邏輯處理,比如埋點統計之類的
[invocation invokeWithTarget:self.objc];
}else {
[super forwardInvocation:invocation];
}
}
@end
複製程式碼
可以看到我們重寫了兩個方法:methodSignatureForSelector:
和forwardInvocation:(NSInvocation *)invocation
,前者是實現方法簽名的,我們可以在這個方法中,直接將我們複製的物件進行方法簽名,然後生成NSInvocation
。接著方法forwardInvocation
會被呼叫,在這個方法中,我們直接將invacation
的target
設定為我們複製的物件。在這個方法中我們可以做一點事情,比如根據類名做一些邏輯,也可以做一些資料埋點之類的。
然後我們看看怎麼使用這個複製忍者的:
我們隨便定義兩個類,併為每個類設定了一個方法:
Parker-Dog.h
#import "Parker-Dog.h"
@implementation Parker_Dog
- (void)bite {
NSLog(@"卡卡西召喚通靈獸Paker並咬住了再不斬!");
}
@end
複製程式碼
Wood.h
#import "Wood.h"
@implementation Wood
- (void)boom{
NSLog(@"變!木頭!...");
}
複製程式碼
呼叫:
//初始化一個木頭
Wood *wood = [[Wood alloc] init];
//初始化一個帕克
Parker_Dog *paker = [[Parker_Dog alloc] init];
//初始化一個卡卡西
KakashiProxy *proxy = [KakashiProxy alloc];
//變木頭
[proxy changeObj:wood];
//呼叫木頭的方法
[proxy performSelector:@selector(boom) withObject:nil];
//變帕克
[proxy changeObj:paker];
//呼叫帕克的方法
[proxy performSelector:@selector(bite) withObject:nil];
複製程式碼
控制檯輸出:
這樣,我們通過proxy
這個類實現了複製wood
和paker
,可以分別呼叫各個類的方法了。
總結
其實也不能叫複製吧,大家也可以看到,這個實現其實就是利用了runtime
的訊息轉發機制。這篇文章就算是對NSProxy
的一個簡單認識吧,還有些NSProxy
的高階用法可能筆者還沒有學習到,還要繼續努力,有時間需要深入研究下這個特殊的類。
參看文章