当我使用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];
虽然您只是通过helloWorld
将class_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的错误?
答案 0 :(得分:9)
不,这不是一个错误。它定义了运行时系统(虽然模糊不清)的行为。
就像每个实例都有一个指向它的类的isa
实例变量一样,内存中的每个类结构都有一个指向元类的isa
成员。就像任何给定的类包含有关其实例的元数据一样 - 包括实例响应的方法列表 - 类的元类包含有关类本身的元数据,包括类响应的方法列表到。
此外,每个类结构都有一个superclass
成员,指向其超类,它在元类层次结构中镜像(即每个元类的superclass
是另一个元类)。
但有一个主要区别:NSObject
的超类是nil
,而NSObject
元类的超类是NSObject
。换句话说,NSObject
的元类继承了NSObject
的实例方法。因此,Objective-C类不仅响应其定义的类方法,还响应NSObject
实例方法。
困惑了吗? Greg Parker撰写了一篇精彩的博客,其中包含一个非常有用的图表,说明了如何将它们连接在一起:
Hamster Emporium archive - Classes and metaclasses
修改强>
唉,互联网。如果您当前使用的浏览器未显示内联PDF文档,则此处是直接指向图表的链接: