NSProxy需要實現哪些方法?為什麼 - forwardingTargetForSelector: 被註釋了? ...
轉註出:https://www.cnblogs.com/xiaobajiu/p/10799962.html
使用NSProxy做替身,代理,多繼承,本質上都是用它來轉發消息給真身。
觀察頭文件,NSProxy自身實現了的方法如下:
+ (Class)class;//類方法不應該重寫
//普通消息轉發1 - (void)forwardInvocation:(NSInvocation *)invocation;//其實自身並沒有實現,調用報錯。需要子類實現。並且官方建議重寫。
//普通消息轉發2 - (nullable NSMethodSignature *)methodSignatureForSelector:(SEL)sel;//可以重寫,並且官方建議重寫。 - (void)dealloc;//可以重寫 - (void)finalize;//應該忽略的方法(垃圾回收) @property (readonly, copy) NSString *description;//可以重寫 @property (readonly, copy) NSString *debugDescription;//可以重寫 + (BOOL)respondsToSelector:(SEL)aSelector;//類方法不應該重寫
另外值得註意的是被註釋的快速轉發消息方法:
// - (id)forwardingTargetForSelector:(SEL)aSelector;
官方明確的暗示我們要使用上上方代碼塊里的普通消息轉發。其實NSproxy子類對象是響應這個方法的,探究這行註釋的原因主要是因為協議<NSObject>
- (BOOL)isEqual:(id)object;//可以重寫,內部只比較地址沒比較哈希 @property (readonly) NSUInteger hash;//可以重寫,註意內部返回的是對象地址<<3 @property (readonly) Class superclass;//可以重寫 - (Class)class;//可以重寫 - (instancetype)self;//可以重寫,一般忽略 - (id)performSelector:(SEL)aSelector;//可以重寫 - (id)performSelector:(SEL)aSelector withObject:(id)object;//可以重寫 - (id)performSelector:(SEL)aSelector withObject:(id)object1 withObject:(id)object2;//可以重寫 - (BOOL)isProxy;//返回YES,一般忽略 - (BOOL)isKindOfClass:(Class)aClass;//被主動轉發到自身的forwardInvocation:中處理 - (BOOL)isMemberOfClass:(Class)aClass;//被主動轉發到自身的forwardInvocation:中處理 - (BOOL)conformsToProtocol:(Protocol *)aProtocol;//被主動轉發到自身的forwardInvocation:中處理 - (BOOL)respondsToSelector:(SEL)aSelector;//如果不能響應也會被主動轉發到自身的forwardInvocation:中處理 - (instancetype)retain OBJC_ARC_UNAVAILABLE; - (oneway void)release OBJC_ARC_UNAVAILABLE; - (instancetype)autorelease OBJC_ARC_UNAVAILABLE; - (NSUInteger)retainCount OBJC_ARC_UNAVAILABLE; - (struct _NSZone *)zone OBJC_ARC_UNAVAILABLE; @property (readonly, copy) NSString *description;//可以重寫 @optional @property (readonly, copy) NSString *debugDescription;//可以重寫
這裡註意到了4個很特殊的方法:
- (BOOL)isKindOfClass:(Class)aClass; - (BOOL)isMemberOfClass:(Class)aClass; - (BOOL)conformsToProtocol:(Protocol *)aProtocol; - (BOOL)respondsToSelector:(SEL)aSelector;
前3個方法直接要求使用普通消息轉發來實現,所以一調用就跳進普通消息轉發從而繞開了快速轉發(- (id)forwardingTargetForSelector:(SEL)aSelector;)
NSProxy並沒有實現forwardInvocation:如果用戶也沒有實現的話它一定會產生崩潰。同理,末尾方法如果自身不能響應依然會要求使用普通消息轉發來實現。
第一個總結:
如果在NSProxy中只想使用快速轉發來完成功能的話就:1.必須單獨實現以上4個方法,或者2.既實現快速轉發又實現普通轉發;顯然1比較划算。
第二個結論:
如果要極盡完全地實現把所有消息都轉發給內部的真身,那麼應該要把上方標記'可以重寫'的方法都重寫了。