Подтвердить что ты не робот

"Тестирование эквивалентности классов" в Objective-c

У меня возникла проблема в понимании этой части "Тестирование равнозначности класса", которая определена в руководстве Apple.

В динамически создаваемом подклассе метод класса обычно переопределяется таким образом, что подкласс маскируется как класс, который он заменяет. При тестировании для равенства классов вы должны сравнивать значения, возвращаемые методом класса, а не те, которые возвращаются функциями нижнего уровня. В терминах API для динамических подклассов используются следующие неравенства:

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

Поэтому вы должны проверить два класса для равенства следующим образом:

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

Ответ 1

Есть ситуации, когда люди добавляют новые классы во время выполнения. Одним из примеров является наблюдение за ключевым значением: когда вы наблюдаете объект, Foundation Framework создает новый подкласс наблюдаемого класса объекта. Этот динамический класс ведет себя так же, как и его суперкласс, но добавляет KVO-уведомления ко всем его мутаторным методам.

В приведенном вами отрывке говорится, что среда выполнения 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, observer - это NSObject

2012-06-08 08: 37: 26.907 Без названия 2 [896: 707] модель является NSKVONotifying_NSObject, наблюдателем является NSObject

2012-06-08 08: 37: 26.907 Untitled 2 [896: 707] модель NSKVONotifying_NSObject, observer - это NSObject

Итак, как показывает документация, это только первый случай (где мы сравниваем -class), который делает все, что мог бы ожидать код приложения. Два других способа узнать класс - задание времени выполнения и отбрасывание указателя на объект Class * - обе выдают детали реализации того, как KVO изменил класс из-под нас, и означают, что сравнение классов теперь выиграло ' t показывают, что классы равны.

Поскольку другие ответы и комментарии относятся к -isMemberOfClass: и -isKindOfClass:, я также рассмотрю эти пункты:

  • -isKindOfClass: не является критерием равенства классов. [object isKindOfClass: aClass] истинно, если object является экземпляром aClass или любого из его подклассов. Поскольку прохождение, которое вы процитировали, касается равенства классов, -isKindOfClass: здесь не имеет значения. Тем не менее, это чаще всего тест, который вы хотите делать в коде приложения. Это чаще встречается в ответе на вопрос "могу ли я использовать этот объект как Foo?"? чем "является ли этот объект экземпляром точно из Foo?".

  • -isMemberOfClass: - это тест для равенства классов: [object isMemberOfClass: aClass] является только true, если объект является экземпляром aClass. Этот тест выполняется с использованием метода -class, что означает, что в этом примере model будет испытывать положительный результат для [model isMemberOfClass: [NSObject class]].

Ответ 2

Это должно быть:

if([objctA isKindOfClass [MyClass class]])

Ответ 3

Может быть, вы можете использовать метод "NSStringFromClass" и сравнить полученные строки с помощью "isEqualToString"?