NSInvocation基本用法

前提:

在 iOS中可以直接調用某個對象的消息方式有兩種:

一種是performSelector:withObject;

再一種就是NSInvocation。

第一種方式比較簡單,能完成簡單的調用。但是對于>2個的參數或者有返回值的處理,那performSelector:withObject就顯得有點有心無力了,那么在這種情況下,我們就可以使用NSInvocation來進行這些相對復雜的操作

NSInvocation的基本使用

方法簽名類

// 方法簽名中保存了方法的名稱/參數/返回值,協同NSInvocation來進行消息的轉發
// 方法簽名一般是用來設置參數和獲取返回值的, 和方法的調用沒有太大的關系
//1、根據方法來初始化NSMethodSignature
NSMethodSignature  *signature = [ViewController instanceMethodSignatureForSelector:@selector(run:)];
根據方法簽名來創建NSInvocation對象

// NSInvocation中保存了方法所屬的對象/方法名稱/參數/返回值
//其實NSInvocation就是將一個方法變成一個對象
//2、創建NSInvocation對象
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
//設置方法調用者
invocation.target = self;
//注意:這里的方法名一定要與方法簽名類中的方法一致
invocation.selector = @selector(run:);
NSString *way = @"byCar";
//這里的Index要從2開始,以為0跟1已經被占據了,分別是self(target),selector(_cmd)
[invocation setArgument:&way atIndex:2];
//3、調用invoke方法
[invocation invoke];
//實現run:方法
- (void)run:(NSString *)method{

}

優化

但是上述方法有很多弊端,首先我們來一一解決

1、如果調用的方法不存在

//此時我們應該判斷方法是否存在,如果不存在這拋出異常
if (signature == nil) {
//aSelector為傳進來的方法
NSString *info = [NSString stringWithFormat:@"%@方法找不到", NSStringFromSelector(aSelector)];
[NSException raise:@"方法調用出現異常" format:info, nil];
}

2、方法的參數個數與外界傳進來的參數數組元素個數不符

//此處不能通過遍歷參數數組來設置參數,因為外界傳進來的參數個數是不可控的
//因此通過numberOfArguments方法獲取的參數個數,是包含self和_cmd的,然后比較方法需要的參數和外界傳進來的參數個數,并且取它們之間的最小值
NSUInteger argsCount = signature.numberOfArguments - 2;
NSUInteger arrCount = objects.count;
NSUInteger count = MIN(argsCount, arrCount);
for (int i = 0; i < count; i++) {
    id obj = objects[i];
    // 判斷需要設置的參數是否是NSNull, 如果是就設置為nil
    if ([obj isKindOfClass:[NSNull class]]) {
        obj = nil;
    }
[invocation setArgument:&obj atIndex:i + 2];
}
3、判斷當前調用的方法是否有返回值

//方法一:
id res = nil;
if (signature.methodReturnLength != 0) {//有返回值
    //將返回值賦值給res
    [invocation getReturnValue:&res];
}
return res;

//方法二:
//可以通過signature.methodReturnType獲得返回的類型編碼,因此可以推斷返回值的具體類型
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 目錄 Objective-C Runtime到底是什么 Objective-C的元素認知 Runtime詳解 應用...
    Ryan___閱讀 1,962評論 1 3
  • 前提: 在 iOS中可以直接調用某個對象的消息方式有兩種:一種是performSelector:withObjec...
    木_木27閱讀 19,322評論 11 71
  • 轉至元數據結尾創建: 董瀟偉,最新修改于: 十二月 23, 2016 轉至元數據起始第一章:isa和Class一....
    40c0490e5268閱讀 1,789評論 0 9
  • 小知識: 在 iOS中可以直接調用某個對象的消息方式有兩種:一種是performSelector:withObje...
    圣僧留步閱讀 1,386評論 0 0
  • 繼上Runtime梳理(四) 通過前面的學習,我們了解到Objective-C的動態特性:Objective-C不...
    小名一峰閱讀 777評論 0 3