Передача экземпляра класса в @protocol в Objective-C

У меня есть объект (UIViewController), который может или не может соответствовать протоколу, который я определил.

Я знаю, что могу определить, соответствует ли объект протоколу, затем безопасно вызовите метод:

if([self.myViewController conformsToProtocol:@protocol(MyProtocol)]) {
    [self.myViewController protocolMethod]; // <-- warning here
}

Однако XCode показывает предупреждение:

warning 'UIViewController' may not respond to '-protocolMethod'

Какой правильный способ предотвратить это предупреждение? Кажется, я не могу отличить self.myViewController как класс MyProtocol.

Ответ 1

Правильный способ сделать это:

if ([self.myViewController conformsToProtocol:@protocol(MyProtocol)])
{
        UIViewController <MyProtocol> *vc = (UIViewController <MyProtocol> *) self.myViewController;
        [vc protocolMethod];
}

UIViewController <MyProtocol> * type-cast переводит на "vc - объект UIViewController, который соответствует MyProtocol", тогда как использование id <MyProtocol> переводит на "vc - объект неизвестного класса, который соответствует MyProtocol".

Таким образом, компилятор даст вам правильную проверку типов на vc - компилятор даст вам предупреждение только в том случае, если вызывается какой-либо метод, который не объявлен ни на UIViewController, либо <MyProtocol>. id следует использовать только в ситуации, если вы не знаете класс/тип объекта, который выполняется.

Ответ 2

Вы можете сделать это следующим образом:

if([self.myViewController conformsToProtocol:@protocol(MyProtocol)])
{
    id<MyProtocol> p = (id<MyProtocol>)self.myViewController;
    [p protocolMethod];
}

Это тоже меня бросило. В Objective-C протокол не является самим типом, поэтому вам нужно указать id (или какой-либо другой тип, например NSObject), а также тот протокол, который вы хотите.