在iOS中方法調(diào)用的方式:
第一種方式
- (id)performSelector:(SEL)aSelector;
- (id)performSelector:(SEL)aSelector withObject:(id)object;
- (id)performSelector:(SEL)aSelector withObject:(id)object1 withObject:(id)object2;
第二種方式
NSInvocation
如果參數(shù)多于兩個,比較適合使用第二種方式
#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:)];//方法有兩個參數(shù)
// 2.對象方法 NSObject中的方法
NSMethodSignature *signature1 = [self methodSignatureForSelector:@selector(eatFood)];//方法有一個參數(shù)
// 3.類方法 NSMethodSignature中的方法
NSMethodSignature *signature = [NSMethodSignature signatureWithObjCTypes:"v@:@"];//此處設(shè)置了一個參數(shù)
//此時我們應(yīng)該判斷方法是否存在藕帜,如果不存在這拋出異常
if (signature == nil) {
//aSelector為傳進(jìn)來的方法
NSString *info = [NSString stringWithFormat:@"%@方法找不到", NSStringFromSelector(@selector(run:))];
[NSException raise:@"方法調(diào)用出現(xiàn)異常" format:info, nil];
}
// 根據(jù)方法簽名來創(chuàng)建NSInvocation對象
//2偿洁、創(chuàng)建NSInvocation對象
NSInvocation *invocaton = [NSInvocation invocationWithMethodSignature:signature];
// 設(shè)置方法調(diào)用者
invocaton.target =self;
// 設(shè)置要調(diào)用的方法
invocaton.selector = @selector(run:);//這里的方法與簽名的方法可以一致也可以不一致赶促,不一致時會調(diào)用此處設(shè)置的方法(可以在此處修改方法)
//numberOfArguments方法獲取的參數(shù)個數(shù),包含self和_cmd埠对,減去2之后才是簽名方法中需要的參數(shù)個數(shù)
NSArray *objects = @[@"a",@"b",@"c"];
NSUInteger argsCount = signature.numberOfArguments-2;//簽名方法的參數(shù)個數(shù)
NSUInteger arrCount = objects.count;
NSUInteger count = MIN(arrCount, argsCount);
for (int i = 0; i<count; i++) {
id obj = objects[i];
// 判斷需要設(shè)置的參數(shù)是否是NSNull, 如果是就設(shè)置為nil
if ([obj isKindOfClass:[NSNull class]]) {
obj = nil;
}
[invocaton setArgument:&obj atIndex:i +2];// 逐個設(shè)置參數(shù)
}
// 這里的Index要從2開始,以為0跟1已經(jīng)被占據(jù)了酬蹋,分別是self(target),selector(_cmd)
// [invocaton setArgument:&objects atIndex:2];//簽名的方法要有參數(shù)身笤,沒有的話,會在此處崩潰斤彼,如果簽名方法的參數(shù)是兩個分瘦,此處設(shè)置一個參數(shù),那么第二個參數(shù)為nil
// NSString *jjj;
// [invocaton getArgument:&jjj atIndex:2];//獲得參數(shù)
// id res = nil;
// if (signature.methodReturnLength != 0) {//有返回值
// //將返回值賦值給res
// [invocaton getReturnValue:&res];//沒有返回值時琉苇,調(diào)用此方法崩潰
// }
[invocaton invoke];//執(zhí)行完方法后嘲玫,在往下執(zhí)行
// NSInteger tag;
// 得到執(zhí)行方法后的返回值
// [invocaton getReturnValue:&tag];//如果執(zhí)行的方法返回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(@"我是賈紅領(lǐng)%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
{
}