iOS开发 - performSelector:传递两个以上参数传、递结构体
▶ 如何传递两个以上的参数
下面用三种方式实现
DemoA:将所有参数放入一个字典或数组传过去!这种方式需要改动要调用方法的取参数的方式,比如使用字典传值时,双方需约定每一个参数放入字典对应的 key 是什么
- (void)viewDidLoad { [super viewDidLoad]; NSDictionary *paramDic = @{@"param1":@"string",@"param2":@[@2,@3,@3],@"param3":@123}; [self performSelector:@selector(testFunctionWithParams:) withObject:paramDic]; } - (void)testFunctionWithParams:(NSDictionary *)paramDic { NSLog(@"%s dic:%@",__FUNCTION__, paramDic); }
DemoB:使用 objc_msgSend() 。利用这种方法可以传递多个参数的特性调用方法执行
- (void)viewDidLoad { [super viewDidLoad]; // 需要引入头文件 #import <objc/message.h> ((void (*)(id,SEL,NSString *, NSArray *, NSInteger))objc_msgSend)(self, @selector(textFunctionWithParam:param2:param3:),@"111",@[@2,@3],123); } -(void)textFunctionWithParam:(NSString *)param1 param2:(NSArray *)param2 param3:(NSInteger)param3 { NSLog(@"param1:%@, param2:%@, param3:%ld",param1, param2, param3); }
DemoC:使用 NSInvocation
1 #import "ViewController.h" 2 @implementation ViewController 3 4 - (void)viewDidLoad { 5 [super viewDidLoad]; 6 7 NSArray *paramArray = [NSArray arrayWithObjects:@"hello", @[@222,@333],@122,nil]; 8 [self performSelector:@selector(textFunctionWithParam:param2:param3:) withObjects:paramArray]; 9 } 10 11 - (id)performSelector:(SEL)selector withObjects:(NSArray *)objects{ 12 13 // 方法签名 14 NSMethodSignature *signature = [[self class] instanceMethodSignatureForSelector:selector]; 15 16 if (signature == nil) { 17 // 可以抛出异常也可以不操作 18 } 19 20 // 通过 NSInvocation对象 包装一次方法调用:方法调用者、方法名、方法参数、方法返回值 21 NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];// 可以使用方法的签名来创建一个 NSInvocation对象 22 invocation.target = self; 23 invocation.selector = selector; 24 25 // NSMethodSignature 有两个常用的只读属性 26 // numberOfArguments 方法参数的个数 27 // methodReturnLength 方法返回值类型的长度,大于 0 表示有返回值 28 NSInteger paramsCount = signature.numberOfArguments - 2; // 除self、_cmd 以外的参数个数 29 paramsCount = MIN(paramsCount, objects.count); 30 31 // 参数 32 for (NSInteger i = 0; i < paramsCount; i++) { 33 id object = objects[i]; 34 if ([object isKindOfClass:[NSNull class]]) continue; 35 36 // 设置参数时必须传递参数的地址 37 // 参数赋值:注意下标从 2 开始,因为 0、1 已经被 target 与 selector 占用 38 [invocation setArgument:&object atIndex:i + 2]; 39 } 40 41 // 调用方法:有返回值类型,才去获得返回值 42 [invocation invoke]; 43 44 // 获取返回值 45 id returnValue = nil; 46 if (signature.methodReturnLength) { 47 // 返回值与设置参数一样,都必须将地址传过去 48 [invocation getReturnValue:&returnValue]; 49 } 50 return returnValue; 51 } 52 53 // 调用的方法 54 -(void)textFunctionWithParam:(NSString *)param1 param2:(NSArray *)param2 param3:(NSString*)param3 { 55 56 NSLog(@"param1:%@, param2:%@, param3:%d",param1, param2, [param3 intValue]); 57 } 58 59 @end
▶ 传递结构体
我们知道 NSNumber 是 NSValue 的子类,但 NSNumber 只能包装数字类型,而 NSValue 可以包装任意值
因此可以用 NSValue 将结构体包装后加入 NSArray或NSDictionary 中,代码如下
#import "ViewController.h" typedef struct MakeStruct{ int x; int y; }testStruct; @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; // 结构体 testStruct testS = {101, 192}; NSValue *valueStruct = [NSValue valueWithBytes:&testS objCType:@encode(testStruct)]; NSDictionary *dataDic = @{@"param1":@"ssfs",@"param2":@[@333,@32343],@"param3":valueStruct}; [self performSelector:@selector(testFunctionWithParams:) withObject:dataDic]; } - (void)testFunctionWithParams:(NSDictionary *)paramDic { NSValue *paramValue = paramDic[@"param3"]; testStruct paramStruct; [paramValue getValue:¶mStruct]; NSLog(@"取出结构体中的 x 值:%d",paramStruct.x); } @end
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)
2018-03-22 iOS第三方 - AFNetworking_2.0版 02:如何使用
2018-03-22 iOS第三方 - AFNetworking_2.0版 01:原理