我在下一个代码中获得指向实例方法的指针:
#import <Foundation/Foundation.h>
#import <objc/runtime.h>
@interface TestClass : NSObject
@end
@implementation TestClass
- (void)someMethod { // This is instance method, it's okay
NSLog(@"Hello from some method!");
}
@end
int main(int argc, const char * argv[]) {
typedef void (*MethodWithoutParams)();
MethodWithoutParams someMethodImplementation =
class_getMethodImplementation([TestClass class], @selector(someMethod));
someMethodImplementation();
return 0;
}
效果很好。但是,如果我想获得指向类方法的指针,它将无法正常工作:
#import <Foundation/Foundation.h>
#import <objc/runtime.h>
@interface TestClass : NSObject
@end
@implementation TestClass
+ (void)someMethod { // This is class method, it doesn't work
NSLog(@"Hello from some method!");
}
@end
int main(int argc, const char * argv[]) {
typedef void (*MethodWithoutParams)();
MethodWithoutParams someMethodImplementation =
class_getMethodImplementation([TestClass class], @selector(someMethod));
someMethodImplementation();
return 0;
}
它无法工作,因为它无法查找方法的实现。
我确信它一定能正常工作,因为如果我以这种方式获得实现,它将能够正常工作:
MethodWithoutParams someMethodImplementation =
[TestClass methodForSelector:@selector(someMethod)];
因此,我研究了NSObject的实现,然后看下面的代码:
+ (IMP)methodForSelector:(SEL)sel {
if (!sel) [self doesNotRecognizeSelector:sel];
return object_getMethodImplementation((id)self, sel);
}
- (IMP)methodForSelector:(SEL)sel {
if (!sel) [self doesNotRecognizeSelector:sel];
return object_getMethodImplementation(self, sel);
}
还object_getMethodImplementation()
函数有下一次执行:
IMP object_getMethodImplementation(id obj, SEL name)
{
Class cls = (obj ? obj->getIsa() : nil);
return class_getMethodImplementation(cls, name);
}
因此,类方法查找和实例方法查找的实现是相同的。
但这是行不通的,我也不知道为什么。我猜想任何类型的方法(类和实例)都将位于调度表中,并且我可以获取指向任何此类方法的指针。但是如您所见,我做不到。
您需要查询类的元类。类方法是其元类上的实例方法。
Class meta = objc_getMetaClass("TestClass");
SEL sel = @selector(someMethod);
typedef void (*MyMethodImplementation)(Class, SEL);
MyMethodImplementation someMethodImplementation = (MyMethodImplementation)class_getMethodImplementation(meta, sel);
someMethodImplementation([TestClass class], sel);
注意,方法(实例或类)永远不会“没有参数”。必须始终至少使用接收者(实例或类)和选择器来调用它。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句