1. 程式人生 > >80_iOS乾貨43_呼叫OC方法傳遞多個引數的11種方法

80_iOS乾貨43_呼叫OC方法傳遞多個引數的11種方法

一,方法中寫多個引數呼叫

- (void)test1 {
    [self testFunctionWithParams1:6 :@"234131#"];
}
- (void)testFunctionWithParams1:(int )number :(NSString *)string {
    NSLog(@"方法多個引數:%i%@",number, string);
}

二,performSelector呼叫方法

#pragma mark -  2,performSelector傳引數:最多兩個引數
- (void)test2 {
    [self performSelector:@selector(testFunctionWithParams1::) withObject:@5 withObject:@"67"];
    
//    動態載入方法:需要對指標做處理,最多兩個引數
//    SEL selector = NSSelectorFromString(@"testFunctionWithParams2::");
//    IMP imp = [self methodForSelector:selector];
//    void (*func)(id, SEL) = (void *)imp;
//    if([self respondsToSelector:selector]){
//        func(self,selector);
//    };
    
//    也可以採用延時,但只能傳一個引數
//    SEL selector = NSSelectorFromString(@"testFunctionWithParams2:");
//    [self performSelector:selector withObject:@"tom" afterDelay:0.1f];
}
- (void)testFunctionWithParams:(NSString *)string {
     NSLog(@"performSelector傳引數:%@", string);
}

- (void)testFunctionWithParams2:(int )number :(NSString *)string {
     NSLog(@"performSelector傳引數:%i%@",number, string);
}

三,傳字典,封裝成物件

#pragma mark -  3,傳字典
- (void)test3 {
    //封裝引數
    NSDictionary *dic = @{@"param1":@"this is a string",@"param2":@[@2,@3,@3],@"param3":@123};
    //呼叫方法
    [self testFunctionWithParams3:dic];
    
}
- (void)testFunctionWithParams3:(NSDictionary *)paramDic {
    NSLog(@"傳字典:%@", paramDic);
}

四,傳結構體,不同型別的引數

#pragma mark - 4,傳結構體
- (void)test4 {
    //傳結構體
    testStruct testS = {10000, @"1234"};
    [self testFunctionWithParams4:testS];
    
}
- (void)testFunctionWithParams4:(testStruct )paramStruct {
   
    NSLog(@"結構體元素aaa = %d",paramStruct.aaa);
    NSLog(@"結構體元素bbb = %@",paramStruct.bbb);
}

五,傳結構體字典

#pragma mark -  5,傳結構體字典
- (void)test5 {
    //傳結構體
    testStruct testS = {10000, @"1234"};
    NSValue *value = [NSValue valueWithBytes:&testS objCType:@encode(testStruct)];
    //dic
    NSDictionary *dataDic = @{@"param1":@"ssfs",@"param2":@[@333,@32343],@"param3":value};
    [self testFunctionWithParams5:dataDic];
    
    
}
- (void)testFunctionWithParams5:(NSDictionary *)paramDic {
    NSLog(@"結構體字典:%@", paramDic);
    NSValue *paramValue = paramDic[@"param3"];
    testStruct paramStrout;
    [paramValue getValue:&paramStrout];
    NSLog(@"結構體字典的元素aaa:%d",paramStrout.aaa);
    
}

六,傳模型

#pragma mark - 6,傳模型
- (void)test6 {
    
    Parameter1 *parameter1 = [Parameter1 new];
    parameter1.number = 14;
    ParameterManager<Parameter1 *> *manager1 = [ParameterManager new];
    manager1.parameter = parameter1;
    [manager1 getParaWithType:MethodType1];
    
}

七,傳指標列表,引數個數不定,但型別一致

#pragma mark -  7,傳指標列表,引數個數不定,但型別一致
- (void)test7 {
    
    /*2,傳同一型別的引數,個數不定 */
    [ParameterManager getType:MethodType0 params:@"23",@"389",@"889",nil];
}

//工具類中的方法實現
/*iOS實現傳遞不定長的多個引數的方法是使用va_list。va_list是C語言提供的處理變長引數的一種方法。在呼叫的時候要在參 數結尾的時候加nil
 va_list的使用需要注意:
 1.首先在函式裡定義va_list型的變數,這個變數是指向引數的指標;
 2.然後用va_start初始化剛定義的va_list變數;
 3.然後用va_arg返回可變的引數,va_arg的第二個引數是你要返回的引數的型別.如果函式有多個可變引數的,依次呼叫va_arg獲取各個引數;
 4.最後用va_end巨集結束可變引數的獲取
 NS_REQUIRES_NIL_TERMINATION,是一個巨集,用於編譯時非nil結尾的檢查。 呼叫時要以nil結尾,否則會崩潰。
 
 */
+ (void)getType:(MethodType)mathod params:(NSString *)string, ...NS_REQUIRES_NIL_TERMINATION {
    
// 1,取出第一個引數
    NSLog(@"傳的第1個引數%@", string);
    
// 2.定義一個指向個數可變的引數列表指標;
    va_list args;
    
// 3.va_start(args, str);string為第一個引數,也就是最右邊的已知引數,這裡就是獲取第一個可選引數的地址.使引數列表指標指向函式引數列表中的第一個可選引數,函式引數列表中引數在記憶體中的順序與函式宣告時的順序是一致的。
    va_start(args, string);
    
    if (string)
    {
        //依次取得除第一個引數以外的引數
// 4.va_arg(args,NSString):返回引數列表中指標所指的引數,返回型別為NSString,並使引數指標指向引數列表中下一個引數。
        // 用於存放取出的引數
        NSString *arg;
        while ((arg = va_arg(args, NSString *)))
        {
            NSLog(@"傳的剩餘引數有:%@",arg);
        };
    }
    //5.清空引數列表,並置引數指標args無效。
    va_end(args);
}

八,runTime的objc_msgSend傳值

#pragma mark -  8,runTime的objc_msgSend傳值
- (void)test8 {
    
//    ((void (*)(id, SEL))objc_msgSend)(self, @selector(test7)); //正確寫法
    
    ((void (*)(id,SEL,NSString *, NSArray *, NSInteger)) objc_msgSend) (self, @selector(textFunctionWithParam8:param2:param3:),@"111",@[@2,@3],123);

}

//有三個引數的方法
-(void)textFunctionWithParam8:(NSString *)param1 param2:(NSArray *)param2 param3:(NSInteger)param3 {
    NSLog(@"param1:%@, param2:%@, param3:%ld",param1, param2, param3);
}

九,NSInvocation傳值

#pragma mark -  9,NSInvocation傳值
- (void)test9 {
    NSArray *paramArray = @[@"112",@[@2,@13],@12];
    [self performNewSelector:@selector(textFunctionWithParam9:param2:param3:) withObjects:paramArray];
    
}
//可以傳多個引數的方法
- (id)performNewSelector:(SEL)selector withObjects:(NSArray *)objects
{
    // 方法簽名(方法的描述)
    NSMethodSignature *signature = [[self class] instanceMethodSignatureForSelector:selector];
    if (signature == nil) {
        
        //可以丟擲異常也可以不操作。
    }
    
    // NSInvocation : 利用一個NSInvocation物件包裝一次方法呼叫(方法呼叫者、方法名、方法引數、方法返回值)
    NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
    invocation.target = self;
    invocation.selector = selector;
    
    // 設定引數
    NSInteger paramsCount = signature.numberOfArguments - 2; // 除self、_cmd以外的引數個數
    paramsCount = MIN(paramsCount, objects.count);
    for (NSInteger i = 0; i < paramsCount; i++) {
        id object = objects[i];
        if ([object isKindOfClass:[NSNull class]]) continue;
        [invocation setArgument:&object atIndex:i + 2];
    }
    
    // 呼叫方法
    [invocation invoke];
    
    // 獲取返回值
    id returnValue = nil;
    if (signature.methodReturnLength) { // 有返回值型別,才去獲得返回值
        [invocation getReturnValue:&returnValue];
    }
    
    return returnValue;
}

//要呼叫的方法
-(void)textFunctionWithParam9:(NSString *)param1 param2:(NSArray *)param2 param3:(NSInteger)param3 {
    NSLog(@"param1:%@, param2:%@, param3:%ld",param1, param2, param3);
}

十,NSTimer 的@selected傳值

#pragma mark -  10,NSTimer 的@selected傳值
- (void)test10 {
    NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
    [dict setObject:@"testString" forKey:@"string"];
    [NSTimer scheduledTimerWithTimeInterval:0.0 target:self selector:@selector(onTimer:) userInfo:dict repeats:NO];
}

- (void)onTimer:(NSTimer *)timer {
    NSString *string = [[timer userInfo] objectForKey:@"string"];
    NSLog(@"NSTimer傳值:%@",string);
}

十一,UIButton的事件傳值

#pragma mark -  11,UIButton 的@selected傳值
/*
 思路:
 1,傳遞的引數,通過button的tag傳遞
 2,寫一個分類,當前方法中,新增事件,不用另起一個方法
 3,直接新增屬性
 4, 獲取btn所屬的控制器,再將控制器要傳遞的引數暴露出來
 5,自定義button
 */
- (void)test11 {
    UIButton * markButton=[[UIButton alloc] initWithFrame:CGRectMake(280, 0, 30, 30)];
    
    markButton.tag = 18;
    NSString *newProperty = @"newValue";
    objc_setAssociatedObject(markButton, @"newProperty", newProperty, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    [markButton addTarget:self action:@selector(addMark:)  forControlEvents:UIControlEventTouchUpInside];
    [markButton setBackgroundColor:[UIColor redColor]];
    [self.view addSubview:markButton];
    

    
}

- (void)addMark:(UIButton *)btn {
    
    NSLog(@"button的tag%ld",(long)btn.tag);
    NSLog(@"button的runtime新增屬性%@",objc_getAssociatedObject(btn,@"newProperty"));
    
}