在某些情况下,人们会在运行时添加新类。一个例子是键值观察:当你观察一个对象时,Foundation 框架会创建一个被观察对象类的新子类。这个动态类的行为与其超类相同,但将 KVO 通知添加到其所有 mutator 方法。
您引用的段落说,Objective-C 运行时可以将这个新类与原始类区分开来。然而,因为它只是 KVO 构建方式的一个实现细节,你不应该知道或关心它。因此,开发人员重写了-class
他们的新类的方法,假装对象仍然是原始类的成员。
如果要检查两个对象是否属于同一类,则必须比较它们的-class
方法的结果(其中考虑了 KVO 之类的技巧),而不是使用运行时函数。
这是一个例子:
#import <Foundation/Foundation.h>
#import <objc/runtime.h>
int main(int argc, const char * argv[])
{
@autoreleasepool {
NSObject *observer = [NSObject new];
NSObject *model = [NSObject new];
[model addObserver: observer forKeyPath: @"count" options: 0 context: NULL];
//using -class methods:
NSLog(@"model is a %@, observer is a %@", [model class], [observer class]);
//casting to Class:
NSLog(@"model is a %@, observer is a %@", *(Class*)model, *(Class*)observer);
//using the runtime:
NSLog(@"model is a %@, observer is a %@", object_getClass(model), object_getClass(observer));
[model removeObserver: observer forKeyPath: @"count" context: NULL];
[model release];
[observer release];
}
return 0;
}
你看我所做的只是创建两个对象,告诉其中一个观察另一个,然后找出它们的类是什么。结果如下:
2012-06-08 08:37:26.904 无标题 2[896:707] 模型是 NSObject,观察者是 NSObject
2012-06-08 08:37:26.907 无标题 2[896:707] 模型是 NSKVONotifying_NSObject,观察者是 NSObject
2012-06-08 08:37:26.907 无标题 2[896:707] 模型是 NSKVONotifying_NSObject,观察者是 NSObject
因此,正如文档所暗示的那样,它只是第一种情况(我们比较的地方-class
)可以执行应用程序代码可以合理预期的任何事情。找出类的另外两种方法——询问运行时,以及将对象指针转换为Class *
a——都泄露了关于 KVO 如何从我们下面改变类的实现细节,并且意味着类比较现在不会显示班级是平等的。
因为其他答案和评论指的是-isMemberOfClass:
and -isKindOfClass:
,所以我也会介绍这些要点:
-isKindOfClass:
不是对阶级平等的测试。[object isKindOfClass: aClass]
如果object
是 的实例aClass
或其任何子类,则为真。因为您引用的段落是关于阶级平等的,-isKindOfClass:
所以在这里不相关。也就是说,这通常是您希望在应用程序代码中进行的测试。更常见的是关心“我可以将此对象用作Foo
?”的答案。而不是“这个对象是一个完全的实例Foo
吗?”。
-isMemberOfClass:
是对类相等性的测试:[object isMemberOfClass: aClass]
仅当 object 是aClass
. 该测试是使用该-class
方法的结果完成的,这意味着在此示例model
中将测试[model isMemberOfClass: [NSObject class]]
.