系统的performSelector方法##
在<NSObject> 的协议中为我们调用SEL方法提供了几个协议方法
- (id)performSelector:(SEL)aSelector; //直接调用方法
- (id)performSelector:(SEL)aSelector withObject:(id)object;//可以传入一个参数
- (id)performSelector:(SEL)aSelector withObject:(id)object1 withObject:(id)object2; //可以传入两个参数
so,问题来了,要是我们需要传入得参数大于两个怎么办?所以我就试试模拟系统调用方法的过程来实现调用方法可以传入多个参数的demo
系统的performSelector怎么调用的呢?##
第一步:根据SEL去实例化方法签名NSMethodSignature(方法签名中有方法的名称,参数和返回值)
NSMethodSignature *signature =[[self class] instanceMethodSignatureForSelector:aSelector];
第二步:判断方法签名是否存在,如果不存在,就不存在这个方法,如果存在,就通过签名拿到NSInvocation对象(NSInvocation中保存了方法所属于的对象|方法名称|参数|返回值等)
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
第三步:判断参数个数,设置NSInvocation的对象设置参数,调用方法
这里注意哦
!!!!!签名中方法参数的个数:签名内部包含了self和_cmd,所以参数从第3个开始
[invocation setTarget:self];
[invocation setSelector:aSelector];
//签名中方法参数的个数,内部包含了self和_cmd,所以参数从第3个开始
NSInteger signatureParamCount = methodSignature.numberOfArguments - 2;
NSInteger requireParamCount = objects.count;
NSInteger resultParamCount = MIN(signatureParamCount, requireParamCount);
for (NSInteger i = 0; i < resultParamCount; i++)
{
id obj = objects[i];
[invocation setArgument:&obj atIndex:i+2];
}
[invocation invoke];
第四步:返回值的处理
id callBackObject = nil;
if(methodSignature.methodReturnLength)
{
[invocation getReturnValue:&callBackObject];
}
return callBackObject;
步骤原理说完了,直接代码,代码亲切##
个人建议把这个方法增加到NSObject的分类中,以后方便调用
温馨提示:代码复制可用,要是喜欢就点个赞。
- (id)performSelector:(SEL)aSelector withObjects:(NSArray *)objects
{
NSMethodSignature *methodSignature = [[self class] instanceMethodSignatureForSelector:aSelector];
if(methodSignature == nil)
{
@throw [NSException exceptionWithName:@"抛异常错误" reason:@"没有这个方法,或者方法名字错误" userInfo:nil];
return nil;
}
else
{
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:methodSignature];
[invocation setTarget:self];
[invocation setSelector:aSelector];
//签名中方法参数的个数,内部包含了self和_cmd,所以参数从第3个开始
NSInteger signatureParamCount = methodSignature.numberOfArguments - 2;
NSInteger requireParamCount = objects.count;
NSInteger resultParamCount = MIN(signatureParamCount, requireParamCount);
for (NSInteger i = 0; i < resultParamCount; i++) {
id obj = objects[i];
[invocation setArgument:&obj atIndex:i+2];
}
[invocation invoke];
//返回值处理
id callBackObject = nil;
if(methodSignature.methodReturnLength)
{
[invocation getReturnValue:&callBackObject];
}
return callBackObject;
}
}
网友评论
[invocation setArgument:&obj atIndex:i+2];
在这句代码调用的时候,不需要判断一下要设置的参数与函数定义的参数类型是否相同吗?如果是类型不同,调用的时候会不会出问题?