Objective-C class_conformsToProtocol() ошибка?

Я столкнулся с каким-то странным поведением в приложении 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, если это имеет значение).

Ответ 1

Используйте NSObject 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: также проверяет суперклассы.

Ответ 2

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

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

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