當你初次進入NSProxy文檔的時候你會發現,這里面方法少的可憐,甚至吝嗇到連init方法都木有!
NS_ROOT_CLASS @interface NSProxy <NSObject> { Class isa; }
+ (id)alloc;
+ (id)allocWithZone:(nullable NSZone *)zone ;
+ (Class)class;
- (void)forwardInvocation:(NSInvocation *)invocation;
- (nullable NSMethodSignature *)methodSignatureForSelector: (SEL)sel
為什么說是掃地僧呢,因為他可攔截任何方法的實現,即使.h方法都沒有聲明的方法,下面直奔主題。
Q:假如我有個CQTeacher類,.m里面有個方法teach:,如何在未申明的時候就可以調用,并且如何實現調用過程中攔截改變其參數???。
- 創建一個自定義的類CQProxy繼承NSProxy在.h中添加一個方法用來將如何傳入的對象,進行轉換。
@interface CQProxy : NSProxy
-(void)transformObjc:(NSObject *)objc;
@end
- .m文件
//0.外界傳入的objc -(void)transformObjc:(NSObject *)objc{ self.objc = objc; }
//1.查詢該方法的方法簽名,自己沒有就去super中去找 -(NSMethodSignature *)methodSignatureForSelector:(SEL)sel{ NSMethodSignature *signature = nil; //找方法簽名 if ([self.objc methodSignatureForSelector:sel]) { signature = [self.objc methodSignatureForSelector:sel]; } else{ signature = [super methodSignatureForSelector:sel]; } return signature; }
//2.調用方法實現
-(void)forwardInvocation:(NSInvocation *)invocation{ if(self.objc){ //設置想要的目標類 [invocation setTarget:self.objc]; //判斷定是否是我們想要的類型 if ([self.objc isKindOfClass:[NSClassFromString(@"CQTeacher") class]]) { //這里,就是攔截參數,設置成我們想要的參數,即不管外界傳的什么參數,我們傳入的參數永遠是iOS NSString *str = @"iOS"; //下標 0,1都被占用了。 我們設置參數必須從2開始 [invocation setArgument:&str atIndex:2]; } //開始調用 [invocation invoke]; } }
看完自定義的CQProxy實現后,我們就可以來測試下是否可調用 攔截,我們在控制器中創建CQTeacher類的對象,然后進行轉換
CQTeacher *teacher = [[CQTeacher alloc] init]; //沒有init方法 只需要alloc即可。 CQProxy *proxy = [CQProxy alloc]; //轉換類 [proxy transformObjc:teacher]; //即使我們傳入的是java打印的卻是iOS //即使我們并沒在好.h申明方法,依舊可以調用 [proxy performSelector:@selector(teach:) withObject:@"java"];