在iOS中方法调用的方式:
第一种方式
- (id)performSelector:(SEL)aSelector;
- (id)performSelector:(SEL)aSelector withObject:(id)object;
- (id)performSelector:(SEL)aSelector withObject:(id)object1 withObject:(id)object2;
第二种方式
NSInvocation
如果参数多于两个,比较适合使用第二种方式
#import "ViewController.h"
#import <objc/message.h>
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
// 方法签名
//初始化NSMethodSignature
// 1.类方法 NSObject中的方法
// NSMethodSignature *signature = [ViewController instanceMethodSignatureForSelector:@selector(run1:eat:)];//方法有两个参数
// 2.对象方法 NSObject中的方法
NSMethodSignature *signature1 = [self methodSignatureForSelector:@selector(eatFood)];//方法有一个参数
// 3.类方法 NSMethodSignature中的方法
NSMethodSignature *signature = [NSMethodSignature signatureWithObjCTypes:"v@:@"];//此处设置了一个参数
//此时我们应该判断方法是否存在,如果不存在这抛出异常
if (signature == nil) {
//aSelector为传进来的方法
NSString *info = [NSString stringWithFormat:@"%@方法找不到", NSStringFromSelector(@selector(run:))];
[NSException raise:@"方法调用出现异常" format:info, nil];
}
// 根据方法签名来创建NSInvocation对象
//2、创建NSInvocation对象
NSInvocation *invocaton = [NSInvocation invocationWithMethodSignature:signature];
// 设置方法调用者
invocaton.target =self;
// 设置要调用的方法
invocaton.selector = @selector(run:);//这里的方法与签名的方法可以一致也可以不一致,不一致时会调用此处设置的方法(可以在此处修改方法)
//numberOfArguments方法获取的参数个数,包含self和_cmd,减去2之后才是签名方法中需要的参数个数
NSArray *objects = @[@"a",@"b",@"c"];
NSUInteger argsCount = signature.numberOfArguments-2;//签名方法的参数个数
NSUInteger arrCount = objects.count;
NSUInteger count = MIN(arrCount, argsCount);
for (int i = 0; i<count; i++) {
id obj = objects[i];
// 判断需要设置的参数是否是NSNull, 如果是就设置为nil
if ([obj isKindOfClass:[NSNull class]]) {
obj = nil;
}
[invocaton setArgument:&obj atIndex:i +2];// 逐个设置参数
}
// 这里的Index要从2开始,以为0跟1已经被占据了,分别是self(target),selector(_cmd)
// [invocaton setArgument:&objects atIndex:2];//签名的方法要有参数,没有的话,会在此处崩溃,如果签名方法的参数是两个,此处设置一个参数,那么第二个参数为nil
// NSString *jjj;
// [invocaton getArgument:&jjj atIndex:2];//获得参数
// id res = nil;
// if (signature.methodReturnLength != 0) {//有返回值
// //将返回值赋值给res
// [invocaton getReturnValue:&res];//没有返回值时,调用此方法崩溃
// }
[invocaton invoke];//执行完方法后,在往下执行
// NSInteger tag;
// 得到执行方法后的返回值
// [invocaton getReturnValue:&tag];//如果执行的方法返回YES,tag为YES,返回NO,tag为NO
// 可以通过signature.methodReturnType获得返回的类型编码,从而可以推断返回值的具体类型
const char *signa = signature.methodReturnType;
NSUInteger length = signature.methodReturnLength;
/**
获得返回的类型编码,因此可以推断返回值的具体类型
返回类型为void,signa=v length=0
返回类型为NSString,signa=@ length=8
返回类型为BOOL,signa=B length=1
*/
// if (tag) {
NSLog(@"我是贾红领%s**%lu",signa,(unsigned long)length);
// }
}
-(BOOL )run2:(NSString *)method eat:(NSString *)eatStr
{
NSLog(@"222:%@***%@",method,eatStr);
return YES;
}
-(void)run1:(NSString *)method eat:(NSString *)eatStr
{
NSLog(@"111:%@***%@",method,eatStr);
}
-(void)run:(NSString *)method
{
NSLog(@"333%@",method);
}
-(void)eatFood
{
}
网友评论