如何获取类方法的选择器?

Ale*_*nev 2 macos objective-c objective-c-runtime selector ios

我有下一个代码,我得到一个指向实例方法的指针:

#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;
}
Run Code Online (Sandbox Code Playgroud)

它的效果非常好.但是,如果我想获得一个指向类方法的指针,它不起作用:

#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;
}
Run Code Online (Sandbox Code Playgroud)

它不起作用,因为它无法查找方法实现.

我确信它必须有效,因为如果我以这种方式获得实现它会起作用:

MethodWithoutParams someMethodImplementation = 
[TestClass methodForSelector:@selector(someMethod)];
Run Code Online (Sandbox Code Playgroud)

所以我查看了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);
}
Run Code Online (Sandbox Code Playgroud)

object_getMethodImplementation()函数下一次执行:

IMP object_getMethodImplementation(id obj, SEL name)
{
    Class cls = (obj ? obj->getIsa() : nil);
    return class_getMethodImplementation(cls, name);
}
Run Code Online (Sandbox Code Playgroud)

因此,类方法查找和实例方法查找的实现都是相同的.

但它不起作用,我不知道为什么.我想任何类型的方法(类和实例)都将位于调度表中,我可以获得指向任何此方法的指针.但是你看,我做不到.

Ken*_*ses 7

您需要查询类的元类.类方法是其元类的实例方法.

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);
Run Code Online (Sandbox Code Playgroud)

注意,方法(实例或类)永远不会"没有参数".必须始终至少使用接收器(实例或类)和选择器调用它.