Ошибка Objective-C class_conformsToProtocol ()? - PullRequest
10 голосов
/ 12 февраля 2011

Я столкнулся со странным поведением в своем приложении для iPhone Objective-C.

Я использую некоторый код для проверки объекта:

if (!class_conformsToProtocol([someVar someFunctionThatReturnsAClass], @protocol(MyProtocol)))
     [NSException raise:@"Invalid Argument" format:@"The variables returned by 'someFunctionThatReturnsAClass' Must conform to the 'myProtocol' protocol in this case."];

Как ни странно, когда у меня есть класс, который выглядит так:

@interface BaseClass : NSObject<MyProtocol>

...

@end

@interface SubClass : BaseClass

...

@end

И когда я вызываю этот фрагмент: class_conformsToProtocol([SubClass class], @protocol(MyProtocol)), он возвращает NO.

Кроме того, этот код не работает:

class_conformsToProtocol([NSString class], @protocol(NSObject)); // also returns NO

Пока этот код возвращает YES:

[NSString conformsToProtocol:@protocol(NSObject)];

Есть ли что-то, что я пропускаю в документах? Или это какая-то ошибка? (Я использую iOS 4.2, если это имеет значение).

Ответы [ 2 ]

14 голосов
/ 12 февраля 2011

Если здесь есть ошибка, она есть в документации.

Согласно источнику, class_conformsToProtocol() использует class_copyProtocolList(), а затем проверяет каждый полученный протокол на соответствие параметру.class_copyProtocolList() задокументировано как только возвращающие протоколы, которые принимает данный класс, но не протоколы, принятые суперклассами.Поэтому class_conformsToProtocol() только проверяет, принимает ли данный класс протокол, а не его суперклассы.

Ошибка документации состоит в том, что class_conformsToProtocol() не описывает это поведение.Тем не менее, документация действительно гласит, что вы, как правило, не должны использовать эту функцию, а вместо этого используйте метод NSObject conformsToProtocol:.

5 голосов
/ 12 февраля 2011

Использовать NSObject s conformsToProtocol: метод.

Вот эксперимент, который я попробовал:

@protocol MyProtocol

- (void) doSomething;

@end

@interface MyClass : NSObject<MyProtocol>
{
}

@end

@implementation MyClass

- (void) doSomething { 
}

@end

@interface MyOtherClass : MyClass
{

}

@end

@implementation MyOtherClass

- (void) doSomething {
}

@end


int main (int argc, const char * argv[]) {
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];

    MyClass *obj_one = [MyClass new];
    BOOL one_conforms = [obj_one conformsToProtocol:@protocol(MyProtocol)];

    MyOtherClass *obj_two = [MyOtherClass new];
    BOOL two_conforms  = [obj_two conformsToProtocol:@protocol(MyProtocol)];
    NSLog(@"obj_one conformsToProtocol: %d", one_conforms);
    NSLog(@"obj_two conformsToProtocol: %d", two_conforms);

    [pool drain];
    return 0;
}

Выход:

obj_one conformsToProtocol: 1
obj_two conformsToProtocol: 1

Принимая во внимание:

MyOtherClass *obj_two = [MyOtherClass new];
BOOL conforms_two = class_conformsToProtocol([obj_two class], @protocol(MyProtocol));
NSLog(@"obj_two conformsToProtocol: %d", conforms_two);

Выход:

obj_two conformsToProtocol: 0

Вердикт:

Это ошибка с class_conformsToProtocol, используйте conformsToProtocol: метод NSObject

В отличие от class_conformsToProtocol, метод NSObject conformsToProtocol: также проверяет суперклассы.

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