直接调用方法
如果你需要从 C 代码调用 Objective-C 方法,你有两种方法:使用 objc_msgSend
,或者获取 IMP
(方法实现函数指针)并调用它。
#import <objc/objc.h>
@implementation Example
- (double)negate:(double)value {
return -value;
}
- (double)invert:(double)value {
return 1 / value;
}
@end
// Calls the selector on the object. Expects the method to have one double argument and return a double.
double performSelectorWithMsgSend(id object, SEL selector, double value) {
// We declare pointer to function and cast `objc_msgSend` to expected signature.
// WARNING: This step is important! Otherwise you may get unexpected results!
double (*msgSend)(id, SEL, double) = (typeof(msgSend)) &objc_msgSend;
// The implicit arguments of self and _cmd need to be passed in addition to any explicit arguments.
return msgSend(object, selector, value);
}
// Does the same as the above function, but by obtaining the method's IMP.
double performSelectorWithIMP(id object, SEL selector, double value) {
// Get the method's implementation.
IMP imp = class_getMethodImplementation([self class], selector);
// Cast it so the types are known and ARC can work correctly.
double (*callableImp)(id, SEL, double) = (typeof(callableImp)) imp;
// Again, you need the explicit arguments.
return callableImp(object, selector, value);
}
int main() {
Example *e = [Example new];
// Invoke negation, result is -4
double x = performSelectorWithMsgSend(e, @selector(negate:), 4);
// Invoke inversion, result is 0.25
double y = performSelectorWithIMP(e, @selector(invert:), 4);
}
objc_msgSend
通过获取方法的 IMP 并调用它来工作。调用最后几个方法的 IMP
s 是缓存的,所以如果你在一个非常紧凑的循环中发送一个 Objective-C 消息,你可以获得可接受的性能。在某些情况下,手动缓存 IMP 可以提供稍好的性能,尽管这是最后的优化。