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

标签 objective-c objective-c-runtime

当我使用 objc 运行时函数 class_addMethod() 将实现注入(inject)到 NSObject 的实例选择器时,它实际上将实现注入(inject)到实例选择器 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 的接口(interface),并向 NSObject 实例和类调用 helloWorld 消息:

// 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];

虽然你只是通过 class_addMethod()helloWorld 实现注入(inject)到 NSObject 实例选择器中,但是注入(inject)后类和实例消息都被解析了:

=> 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()的目标类是NSObject<时,class_addMethod()才会将实现同时添加到类选择器和实例选择器中

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

最佳答案

不,这不是错误。它是运行时系统的已定义(虽然晦涩)行为。

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

此外,每个类结构都有一个指向其父类(super class)的superclass成员,它反射(reflect)在元类层次结构中(即,每个元类的superclass是另一个元类) .

不过有一个主要区别:NSObject 的父类(super class)是 nil,而 NSObject 元类的父类(super class)是 NSObject。也就是说,NSObject的元类继承了NSObject的实例方法。因此,Objective-C 类不仅响应它们定义的类方法,它们还响应 NSObject 实例方法。

还在迷茫吗? Greg Parker 写了一篇很棒的博客,其中包含一个非常有用的图表,说明了这一切是如何连接在一起的:

Hamster Emporium archive - Classes and metaclasses

编辑

唉,互联网。如果您当前使用的浏览器不显示内联 PDF 文档,这里有一个直接指向图表的链接:

Hamster Emporium archive - class diagram

关于objective-c - 为什么 objc 运行时函数 `class_addMethod()` 在目标类为 `NSObject` 时将实现添加为实例和类方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20300924/

相关文章:

objective-c - 这行代码的目的是什么?

c++ - 如何在 C++ 中按名称检索 Cocoa 枚举值?

objective-c - 在 objc_SetAssociatedObject 中使用非 id 指针作为值是否可以?

objective-c - 传递带有核心日期 + Magical Record 的 ManagedContext

ios - 为什么自动布局忽略了一些约束?

ios - 如何在工作区中使用子项目的标题? [图片]

cocoa - 如何在运行时在 NSButton 上独立缩放轴

ios - 将对象转换(或复制)到 Objective-C 中的子类实例

ios - C功能指针到SEL

iphone - 如何在UITextfield中多次输入文本