Насколько полезен метод - [NSObject isMemberOfClass:]? - PullRequest
10 голосов
/ 21 декабря 2008

Вот небольшая тестовая программа, которую я написал:

#import <Foundation/Foundation.h>

int main(int argc, char **argv) {   
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
    NSArray *arr = [NSArray array];
    printf("Arr isMemberOfClass NSArray: %d\n", [arr isMemberOfClass:[NSArray class]]);
    printf("Arr isKindOfClass NSArray: %d\n", [arr isKindOfClass:[NSArray class]]); 

    [pool release];
    return 0;
}  

И его вывод:

$ ./ismemberof   
Arr isMemberOfClass NSArray: 0   
Arr isKindOfClass NSArray: 1   

Насколько полезен метод -isMemberOfClass: в любом из базовых классов? Я понимаю, что это может дать желаемые результаты для классов, которые я подкласс, но что касается базовых классов - я считаю, что результат false для моей переменной arr неинтуитивен. Является ли это причиной того, что NSArray - это не конкретный класс, а абстрактный класс, а под капотом NSArray действительно конкретный экземпляр NSCFArray?

Ответы [ 3 ]

26 голосов
/ 21 декабря 2008

Вы обычно хотите isKindOfClass:, а не isMemberOfClass:. Разница в том, что isKindOfClass: вернет YES, если получатель является членом подкласса рассматриваемого класса, тогда как isMemberOfClass: вернет NO в том же случае.

Как указывает Грэм Ли, NSArray - это кластер классов. Это означает, что каждый экземпляр NSArray на самом деле является экземпляром некоторого подкласса - отсюда и ваши выводы. Только isKindOfClass: полезен для тестирования принадлежности к классам с кластерами классов.

Тем не менее, вы обычно должны использовать respondsToSelector:, а не тестирование на членство в классе. Одним из примеров будет objectEnumerator, который также реализуется NSSet и NSDictionary (оба из которых также являются кластерами классов). Исключением будет сериализация plist: наборы не являются списками свойств, поэтому вам нужно отправить allObjects на ваш набор, чтобы получить массив, прежде чем пытаться получить из него данные plist.

17 голосов
/ 06 июля 2009

-isMemberOfClass: полезен при реализации метода -isEqual: в ваших собственных классах. Если у вас есть такой класс:

@interface Person : NSObject {
    NSString *name;
    NSUInteger age;
}
@property(copy) NSString *name;
@property(assign) NSUInteger age;
@end

И вы хотите, чтобы два объекта Person считались идентичными, если они имеют одинаковые имя и возраст, вы должны реализовать -isEqual: и метод -hash из протокола NSObject::

- (BOOL)isEqual:(id)obj {
    return [obj isMemberOfClass:[self class]]
        && [obj name] == self.name
        && [obj age] == self.age;
}

- (NSUInteger)hash {
    return [self.name hash] + age;
}

PS: зачем использовать [obj isMemberOfClass:[self class]], а не просто [obj class] == [self class]? В приведенном выше коде это не имеет большого значения, но становится важным, когда вы имеете дело с более сложным кодом, использующим NSProxy. IsMemberOfClass: метод запросит объект, в котором находится прокси, если это член этого класса, что, вероятно, то, что вы хотите.

2 голосов
/ 21 декабря 2008

Я никогда не использовал -isMemberOfClass: себя, потому что, если я добавил функциональность к существующему классу, это обычно происходило посредством добавления методов, поэтому -respondsToSelector: дал мне то, что мне нужно. С другой стороны, я вижу, как полезно узнать, какой именно класс вы смотрите (пример). Например, если вы имеете дело с NSConstantString или NSSimpleCString, вы можете быть более склонны делать предположения относительно -fastestEncoding, чем с экземплярами других классов.

Чтобы ответить на вопрос в теле, да, вы правы. NSArray реализован как кластер классов, поэтому вы не увидите объект, который isMemberOfClass: [NSArray class]. Это не делает -isMemberOfClass: бессмысленным, это просто означает, что это никогда не относится к NSArray.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...