iOS NSInvocation應用與理解

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

相關文章
相關標籤/搜索