IOS中有一個類型是SEL,它的做用很類似與函數指針,經過performSelector:withObject:函數能夠直接調用這個消息。可是perform相關的這些函數,有一個侷限性,其參數數量不能超過2個,不然要作很麻煩的處理,與之相對,NSInvocation也是一種消息調用的方法,而且它的參數沒有限制。這兩種直接調用對象消息的方法,在IOS4.0以後,大多被block結構所取代,只有在很老的兼容性系統中才會使用,簡單用法總結以下:函數
1、初始化與調用測試
在官方文檔中有明確說明,NSInvocation對象只能使用其類方法來初始化,不可以使用alloc/init方法。它執行調用以前,須要設置兩個方法:setSelector: 和setArgument:atIndex:指針
- (void)viewDidLoad { [super viewDidLoad]; SEL myMethod = @selector(myLog); //建立一個函數簽名,這個簽名能夠是任意的,但須要注意,簽名函數的參數數量要和調用的一致。 NSMethodSignature * sig = [NSNumber instanceMethodSignatureForSelector:@selector(init)]; //經過簽名初始化 NSInvocation * invocatin = [NSInvocation invocationWithMethodSignature:sig]; //設置target [invocatin setTarget:self]; //設置selecteor [invocatin setSelector:myMethod]; //消息調用 [invocatin invoke]; } -(void)myLog{ NSLog(@"MyLog"); }
注意:簽名函數的參數數量要和調用函數的一致。測試後發現,當簽名函數參數數量大於被調函數時,也是沒有問題的。code
調用多參數的方法,咱們能夠這樣寫:orm
- (void)viewDidLoad { [super viewDidLoad]; SEL myMethod = @selector(myLog:parm:parm:); NSMethodSignature * sig = [[self class] instanceMethodSignatureForSelector:myMethod]; NSInvocation * invocatin = [NSInvocation invocationWithMethodSignature:sig]; [invocatin setTarget:self]; [invocatin setSelector:myMethod2]; int a=1; int b=2; int c=3; [invocatin setArgument:&a atIndex:2]; [invocatin setArgument:&b atIndex:3]; [invocatin setArgument:&c atIndex:4]; [invocatin invoke]; } -(void)myLog:(int)a parm:(int)b parm:(int)c{ NSLog(@"MyLog%d:%d:%d",a,b,c); }
注意:一、這裏設置參數的Index 須要從2開始,由於前兩個被selector和target佔用。下面這樣寫也沒有任何問題:對象
- (void)viewDidLoad { [super viewDidLoad]; SEL myMethod = @selector(myLog:parm:parm:); SEL myMethod2 = @selector(myLog); NSMethodSignature * sig = [[self class] instanceMethodSignatureForSelector:myMethod]; NSInvocation * invocatin = [NSInvocation invocationWithMethodSignature:sig]; ViewController * view = self; [invocatin setArgument:&view atIndex:0]; [invocatin setArgument:&myMethod2 atIndex:1]; int a=1; int b=2; int c=3; [invocatin setArgument:&a atIndex:2]; [invocatin setArgument:&b atIndex:3]; [invocatin setArgument:&c atIndex:4]; [invocatin retainArguments]; [invocatin invoke]; } -(void)myLog:(int)a parm:(int)b parm:(int)c{ NSLog(@"MyLog%d:%d:%d",a,b,c); }
二、這裏的傳參方式必須是傳遞參數地址。內存
2、NSInvocation的返回值文檔
NSInvocation對象,是能夠有返回值的,然而這個返回值,並非其所調用函數的返回值,須要咱們手動設置:get
- (void)viewDidLoad { [super viewDidLoad]; SEL myMethod = @selector(myLog:parm:parm:); NSMethodSignature * sig = [[self class] instanceMethodSignatureForSelector:myMethod]; NSInvocation * invocatin = [NSInvocation invocationWithMethodSignature:sig]; [invocatin setTarget:self]; [invocatin setSelector:myMethod2]; ViewController * view = self; int a=1; int b=2; int c=3; [invocatin setArgument:&view atIndex:0]; [invocatin setArgument:&myMethod2 atIndex:1]; [invocatin setArgument:&a atIndex:2]; [invocatin setArgument:&b atIndex:3]; [invocatin setArgument:&c atIndex:4]; [invocatin retainArguments]; //咱們將c的值設置爲返回值 [invocatin setReturnValue:&c]; int d; //取這個返回值 [invocatin getReturnValue:&d]; NSLog(@"%d",d); } -(int)myLog:(int)a parm:(int)b parm:(int)c{ NSLog(@"MyLog%d:%d:%d",a,b,c); return a+b+c; }
注意:這裏的操做傳遞的都是地址。若是是OC對象,也是取地址。it
3、關於內存
能夠注意到- (void)retainArguments;這個方法,它會將傳入的全部參數以及target都retain一遍。
專一技術,熱愛生活,交流技術,也作朋友。
——琿少 QQ羣:203317592