为什么objc运行时函数`class_addMethod()`在目标类为'NSObject`时将实现添加为实例和类方法?

时间:2013-11-30 13:40:34

标签: objective-c objective-c-runtime

当我使用objc运行时函数class_addMethod()向NSObject的实例选择器注入实现时,它实际上将实现注入实例选择器 AND 类选择器:

@implementation HelloWorldClass
- (void) helloWorld{
    NSLog(@"hello world from instance method -helloWorld");
}
@end

// ====
// Do method injection when the application did finish launching.
Class sourceClass = objc_getClass("HelloWorldClass");
Class targetClass = objc_getClass("NSObject");
SEL helloWorldSelector = @selector(helloWorld);

Method method = class_getInstanceMethod(sourceClass, helloWorldSelector);
IMP imp = method_getImplementation(method);
const char *methodTypeEncoding = method_getTypeEncoding(method);

class_addMethod(targetClass, helloWorldSelector, imp, methodTypeEncoding);

现在我们只通过Objc Category声明helloWorld的接口,并向helloWorld实例和类调用NSObject消息:

// Declare the interface for `helloWorld
@interface NSObject (HelloWorld)
+ (void) helloWorld;
- (void) helloWorld;
@end


// Send the `helloWorld` message to NSObject class
NSLog(@"Send the `helloWorld` message to NSObject class");
[NSObject helloWorld];

// Send the `helloWorld` message to NSObject instance
NSLog(@"Send the `helloWorld` message to NSObject instance");
[[NSObject new] helloWorld];

虽然您只是通过helloWorldclass_addMethod()实现注入NSObject实例选择器,但是在注入后会解析类和实例消息:

=> Send the `helloWorld` message to NSObject class
=> hello world from instance method -helloWorld
=> Send the `helloWorld` message to NSObject instance
=> hello world from instance method -helloWorld

经过测试,我发现只有class_addMethod()的目标类为class_addMethod()时,NSObject才会将实现添加到类和实例选择器中。

它是objc-runtime还是Cocoa的错误?

1 个答案:

答案 0 :(得分:9)

不,这不是一个错误。它定义了运行时系统(虽然模糊不清)的行为。

就像每个实例都有一个指向它的类的isa实例变量一样,内存中的每个类结构都有一个指向元类isa成员。就像任何给定的类包含有关其实例的元数据一样 - 包括实例响应的方法列表 - 类的元类包含有关类本身的元数据,包括响应的方法列表到。

此外,每个类结构都有一个superclass成员,指向其超类,它在元类层次结构中镜像(即每个元类的superclass是另一个元类)。

但有一个主要区别:NSObject的超类是nil,而NSObject元类的超类是NSObject。换句话说,NSObject的元类继承了NSObject的实例方法。因此,Objective-C类不仅响应其定义的类方法,还响应NSObject实例方法。

困惑了吗? Greg Parker撰写了一篇精彩的博客,其中包含一个非常有用的图表,说明了如何将它们连接在一起:

Hamster Emporium archive - Classes and metaclasses

修改

唉,互联网。如果您当前使用的浏览器未显示内联PDF文档,则此处是直接指向图表的链接:

Hamster Emporium archive - class diagram