天天看點

不一樣的方式實作performSelector接收多個參數(轉) 原文連結:http://www.jianshu.com/p/0c45b496686a

原文連結:http://www.jianshu.com/p/0c45b496686a

字數682  閱讀263  評論4  喜歡2

開發中偶爾有需求使用performSelector實作多個參數,

正常的方式是自定義一個performSelector方法并接收一個數組作為參數

在方法内部通過周遊數組,擷取方法的參數,這确實是個好方法,

不過當我們需要給某個參數傳遞nil的時候,這個方法就不适用了,因為數組中不能存nil

下面嘗試一種非正常的方法,請看~

/// 該方法接收一個方法的簽名,和一個可變參數
- (id)performSelector:(SEL)aSelector withObjects:(id)object,... {

    // 方法簽名(方法的描述)
    NSMethodSignature *signature = [[self class] instanceMethodSignatureForSelector:aSelector];
    if (signature == nil) {
        NSAssert(false, @"牛逼的錯誤,找不到 %@ 方法",NSStringFromSelector(aSelector));
    }
    // 包裝方法
    NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
    // 設定方法調用者
    invocation.target = self;
    // 設定需要調用的方法
    invocation.selector = aSelector;
    // 擷取除去self、_cmd以外的參數個數
    NSInteger paramsCount = signature.numberOfArguments - ;
    // 設定參數
    va_list params;
    va_start(params, object);
    int i = ;
    // [GKEndMark end] 是自定義的結束符号,僅此而已,進而使的該方法可以接收nil做為參數
    for (id tmpObject = object; (id)tmpObject != [GKEndMark end]; tmpObject = va_arg(params, id)) {
        // 防止越界
        if (i >= paramsCount) break;
        // 去掉self,_cmd是以從2開始
        [invocation setArgument:&tmpObject atIndex:i + ];
        i++;
    }
    va_end(params);
    // 調用方法
    [invocation invoke];
    // 擷取傳回值
    id returnValue = nil;
    if (signature.methodReturnType) {
        [invocation getReturnValue:&returnValue];
    }
    return returnValue;
}
​
           

下面是自定義的結束符号類的具體實作

#import "GKEndMark.h"
@implementation GKEndMark
+ (instancetype)end {
    static id instance = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        instance = [[self class] new];
    });
    return instance;
}
@end
           

具體使用

- (void)viewDidLoad {
    [super viewDidLoad];
    // [GKEndMark end] 為自定義的結束符号,你也可以自己随便自定義一個~ 隻是為了讓參數可以傳nil
    NSString * resultStr = [self performSelector:@selector(resultStringWithStr1:str2:str3:) withObjects:@"大神",nil,@"帶我飛",@"飛飛飛",[GKEndMark end]];

    NSLog(@"輸出結果 %@",resultStr);
}

- (NSString *)resultStringWithStr1:(NSString *)str1 str2:(NSString *)str2 str3:(NSString *)str3 {

    NSLog(@"各參數的值: str1 = %@ , str1 = %@, str1 = %@",str1, str2, str3);

    NSString * str = str1;
    if (str2) {
       str =  [str1 stringByAppendingString:str2];
    }

    if (str3) {
        return [str stringByAppendingString:str3];
    }
    return str;
}
           

控制台輸出結果如下

不一樣的方式實作performSelector接收多個參數(轉) 原文連結:http://www.jianshu.com/p/0c45b496686a

Paste_Image.png

以上為方法的具體實作,已經做了詳細的注釋了,就不多做解釋了,

不過該方法還有個局限性就是

當調用的方法傳回值不是對象類型時就會崩了

(不過系統的這類似的方法也沒有傳回基本資料類型的,不知道是不是我想太多了)

想了蠻久不知道該如何解決,如果你有好的解決方案,請聯系我,謝謝~

需要用到資料庫的請看:http://www.jianshu.com/p/0e598147debc