Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/objective-c/27.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Objective c 当目标类为“NSObject”时,为什么objc运行时函数“class_addMethod()”将实现添加为实例和类方法?_Objective C_Objective C Runtime - Fatal编程技术网

Objective c 当目标类为“NSObject”时,为什么objc运行时函数“class_addMethod()”将实现添加为实例和类方法?

Objective c 当目标类为“NSObject”时,为什么objc运行时函数“class_addMethod()”将实现添加为实例和类方法?,objective-c,objective-c-runtime,Objective C,Objective C Runtime,当我使用objc运行时函数class_addMethod()将实现注入NSObject的实例选择器时,它实际上将实现注入实例选择器和类选择器: @implementation HelloWorldClass - (void) helloWorld{ NSLog(@"hello world from instance method -helloWorld"); } @end // ==== // Do method injection when the application did f

当我使用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);
现在我们只需通过Objc Category声明
helloWorld
的接口,并向
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\u addMethod()
helloWorld
实现注入到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\u addMethod()
仅当
class\u addMethod()
的目标类是
NSObject
时,才将实现添加到类和实例选择器中


这是objc运行时的bug还是Cocoa的bug?

不,这不是bug。它定义了运行时系统的行为(尽管很模糊)

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

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

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

困惑了吗?格雷格·帕克(Greg Parker)写了一篇优秀的博客,其中包括一张非常有用的图表,说明了这一切是如何联系在一起的:

编辑

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


这是否可以仅将实现添加到
NSObject
的实例方法列表中?使用
class\u addMethod()
时,向
NSObject
类和实例方法注入任何好处吗?您的代码只将实现添加到实例方法列表中,但
NSObject
的元类继承了其所有实例方法;你所描述的行为就是这样的结果。就我所知,添加与类方法相同的方法不会有任何实际区别。您可以尝试ping以获得更明确的答案。非常感谢您的回答和评论。但是我仍然不明白为什么
NSObject
的元类应该继承它的所有实例方法。希望能回答这个问题。:)我不确定你的问题是存在主义的还是实际的。你的意思是“为什么”吗?从“语言的设计者为什么做出这种特殊的选择?”的意义上说,为了让Objective-C类成为消息的目标,它还必须能够正确地执行实例行为。因此,其元类中的方法列表不仅必须具有类方法,还必须具有定义基本对象行为的实例方法,例如
respondsToSelector:
,等等。