Параметр Introspect типа: id, чтобы определить, является ли это классом или протоколом - PullRequest
1 голос
/ 21 сентября 2011

У меня есть следующий метод:

-(void)SomeMethod:(id)classOrProtocol;

Он будет называться так:

[self someMethod:@protocol(SomeProtocol)];

Или

[self someMethod:[SomeClass class]];

В теле метода, которое мне нужнорешить, если | classOrProtocol |is:

Любой класс (класс) ИЛИ любой протокол (протокол) ИЛИ что-нибудь еще

[[classOrProtocol class] isKindOfClass: [Protocol class]]

В результате возникает ошибка (build):

Receiver 'Протокол - это прямой класс, и соответствующий @interface может не существовать

Итак, как я могу отличить протокол от класса от чего-либо еще?

Ответы [ 2 ]

2 голосов
/ 21 сентября 2011

В Objective-C 2 (то есть, если вы не используете 32-разрядную среду выполнения в OS X) Protocol определен как простой класс, см. /usr/include/objc/runtime.h. Настоящий интерфейс нигде не объявлен. Вы можете попытаться включить /usr/inlcude/objc/Protocol.h, сказав

#import <objc/Protocol.h>

но, как написано там, ни один метод не поддерживается публично для экземпляра Protocol. Единственный приемлемый способ иметь дело с Protocol экземплярами - это использовать функции времени выполнения, приведенные в Objective-C Runtime Reference . Даже публично не определено, является ли Protocol подклассом чего-либо, и даже не говорится, что он реализует протокол NSObject. Таким образом, вы не можете вызвать какой-либо метод.

Конечно, вы можете использовать исходный код среды выполнения, чтобы увидеть, что происходит. Protocol наследуется от Object (который является остатком от pre-OpenStep NeXTSTep), а не от NSObject. Таким образом, вы не можете использовать знакомые методы для NSObject -производных объектов, включая Class из NSObject -производных объектов. См. Открытые реализации Protocol.h и Protocol.m . Как вы видите, класс Protocol сам по себе ничего не делает, потому что каждый метод просто приводит self к protocol_t и вызывает функцию. Фактически, как видно из функции _read_images и других в objc-runtime-new.mm, указатель isa объекта Protocol устанавливается вручную , когда исполняемый файл и библиотеки загружены и никогда не используются.

Итак, не пытайтесь проверить, является ли id Protocol или нет.

Если вам действительно нужно это сделать, вы можете использовать

id foo=...;
if(foo->isa==class_getClass("Protocol")){
    ...
}

Но, если серьезно, не делай этого.

0 голосов
/ 21 сентября 2011

Это не проблема, вызванная невозможностью определить, является ли это классом или протоколом.Ошибка «вызвана отсутствием интерфейса класса Protocol.Убедитесь, что вы импортируете Protocol.m вверху вашего файла реализации, где вы проверяете тип аргумента.

Вы также можете попробовать использовать функцию NSClassFromString(), которая вернет объект Class или nil.Обратите внимание, что если возвращается nil, это не означает, что аргумент является протоколом.Это просто означает, что это также может быть неопределенный класс!

Существует также метод NSProtocolFromString, который возвращает соответствующие результаты - Протокол для протокола и nil для неопределенного протокола.

...