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

 看人生愤怒 发布于 2023-02-13 17:30

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

@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);

现在我们只声明helloWorldvia Objc Category 的接口,并将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];

虽然您只是将helloWorld实现注入到NSObject实例选择器中class_addMethod(),但是在注入之后解析了类和实例消息:

=> 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()is 时才将实现添加到类和实例选择器中NSObject.

它是objc-runtime还是Cocoa的bug?

1 个回答
  • 不,这不是一个bug.它定义了运行时系统(虽然模糊不清)的行为.

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

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

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

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

    Hamster Emporium存档 - 类和元类

    编辑

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

    Hamster Emporium档案 - 类图

    2023-02-13 17:32 回答
撰写答案
今天,你开发时遇到什么问题呢?
立即提问
热门标签
PHP1.CN | 中国最专业的PHP中文社区 | PNG素材下载 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有