iOS调用一个方法基本上有四种方式:1)直接对类调用类方法,对象调用对象方法。2)使用performSelector的方式调用。3)使用NSInvocation调用方法。4)使用runtime,ojbc_msgSend调用。
1)直接调用
[self getPropertyList];
[self getIvarList];
[self getInstanceMethodList];
[self getClassMethodList];
2)使用performSelector的方式调用,
performSelector是运行时系统负责去找方法的,在编译时候不做任何校验;如果直接调用编译是会自动校验。如果imageDownloader:didFinishWithImage:image:不存在,那么直接调用在编译时候就能够发现(借助Xcode可以写完就发现),但是使用performSelector的话一定是在运行时候才能发现(此时程序崩溃);Cocoa支持在运行时向某个类添加方法,即方法编译时不存在,但是运行时候存在,这时候必然需要使用performSelector去调用。所以有时候如果使用了performSelector,为了程序的健壮性,会使用检查方法
if ([obj.observer respondsToSelector:obj.selecotr]) { [obj.observer performSelector:obj.selecotr withObject:obj]; }
3)使用NSInvocation去调用方法
//创建一个函数签名,这个签名可以是任意的,但需要注意,签名函数的参数数量要和调用的一 致。 SEL myMethod =@selector(privateMethod); //通过签名初始化 NSMethodSignature* sig = [NSNumber instanceMethodSignatureForSelector:@selector(init)]; NSInvocation* invocatin = [NSInvocation invocationWithMethodSignature:sig]; //设置target [invocatin setTarget:self]; //设置selecteor [invocatin setSelector:myMethod]; //消息调用 [invocatin invoke];
注意:1、这里设置参数的Index 需要从2开始,因为前两个被selector和target占用。下面这样写也没有任何问题:2、这里的传参方式必须是传递参数地址。
4)objc_msgSend的写法要复杂一点,具体可以参看这篇文章,讲的很清楚
http://www.jianshu.com/p/efeb33712445
但是有个缺点是,需要指定好传递参数的类型,是不是可以直接都用id呢?
经测试id可用
// objc_msgSend SEL sel = NSSelectorFromString(@"printWithString:withNum:withArray:"); ((void (*) (id, SEL, NSString *, NSNumber *, NSArray *)) objc_msgSend) (self, sel, str, num, arr);