29

我在理解苹果指南中定义的“测试类平等”的这一部分时遇到问题。

在动态创建的子类中,类方法通常被重写,以便子类伪装成它所替换的类。因此,在测试类相等性时,您应该比较类方法返回的值,而不是低级函数返回的值。就 API 而言,以下不等式适用于动态子类:

[object class] != object_getClass(object) != *((Class*)object)

因此,您应该测试两个类的相等性,如下所示:

if ([objectA class] == [objectB class]) { //...
4

3 回答 3

42

在某些情况下,人们会在运行时添加新类。一个例子是键值观察:当你观察一个对象时,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]].

于 2012-06-08T07:18:56.643 回答
3

它应该是:

if([objctA isKindOfClass [MyClass class]])
于 2012-06-08T07:11:15.827 回答
1

Maybe can you use the 'NSStringFromClass' method and compare the obtained strings thanks to 'isEqualToString' ?

于 2016-09-13T06:11:58.637 回答