Передайте екземпляр класу до @protocol в Objective-C


102

У мене є об'єкт (UIViewController), який може або не відповідає протоколу, який я визначив.

Я знаю, що можу визначити, чи відповідає об'єкт протоколу, і тоді безпечно викликати метод:

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

Однак XCode показує попередження:

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

Який правильний спосіб запобігти цьому попередженню? Я не можу, здається, виступати self.myViewControllerяк MyProtocolклас.

Відповіді:


171

Правильний спосіб це зробити:

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

UIViewController <MyProtocol> *Типу литих переводить до «ВХ об'єкт UIViewController , який відповідає MyProtocol», тоді як використання id <MyProtocol>призводить до «ВК є об'єктом невідомого класу , який відповідає MyProtocol».

Таким чином компілятор надасть вам належну перевірку типу vc- компілятор видасть вам попередження лише у тому випадку, якщо будь-який метод, який не оголошено ні на або, UIViewControllerні <MyProtocol>на виклик. idслід використовувати лише в тій ситуації, якщо ви не знаєте клас / тип об'єкта, що передається.


2
Під час використання протоколів вам дійсно не варто піклуватися про тип об'єкта - вся суть протоколу полягає в тому, що будь-який тип об'єкта може його прийняти та використовувати без необхідності привласнення до конкретного об'єкта. Отже, я б рекомендував використовувати відповідь від @andy в будь-якому місці, де ви звертаєтесь до протоколу замість вищезазначеного. id<MyProtocol> p = (id<MyProtocol>)self.myViewController;Ця відповідь і @andys є правильними, але його більш правильним.
пам’ятки

2
@Answerbot ваш коментар невірний і пропускає пункт, який я зробив в останньому абзаці своєї відповіді. Ви можете або не піклуєтесь про тип об'єкта, це залежить від ситуації. Що станеться , якщо ви хочете відправити повідомлення оголошено UIViewControllerв vcв прикладі в моїй обороні, і це оголошено як id <MyProtocol>?
Нік Форж

Не впевнений, що щодо мого коментаря невірно? У будь-якому випадку, якщо ви перевіряєте, чи відповідає об'єкт протоколу, то чому б ви тоді називали якийсь інший метод, не пов'язаний з протоколом? Я не можу згадати, коли б мені потрібно було це робити чи бачити це в переглянутому коді. Мені це здається кодовим запахом.
пам’ятки

Тільки тому, що ви його не бачили / не використовували, не означає, що це кодовий запах. Ось фрагмент коду, який показує один приклад того, як викидати інформацію про тип за допомогою id- це проблема: gist.github.com/nsforge/7743616
Nick Forge

60

Ви можете подати його так:

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

Це і мене трохи закинуло. У Objective-C протокол не є самим типом, тому вам потрібно вказати id(або якийсь інший тип, наприклад NSObject) разом з потрібним протоколом.


Ах, круто, дякую. Я щойно перевірив і побачив, що це також (id)працює як лиття . Це погана форма?
Форд

1
Якщо ви призначите його як id <MyProtocol>, тоді компілятор попередить вас, якщо ви використовуєте методи, не визначені в цьому протоколі.
dreamlax

1
@dreamlax - Ось як компілятор перевіряє тип протоколів. Див. Developer.apple.com/documentation/Cocoa/Conceptual/ObjectiveC/… для отримання додаткової інформації.
Енді

1
@Ford - було б краще використовувати протокол спеціально, оскільки таким чином компілятор може виконати певну перевірку типу для вас.
Енді

1
@Andy, я не думаю, що тобі потрібен "*", оскільки "id" - це вже вказівник. Отже: id <MyProtocol> p = (id <MyProtocol>) self.myViewController; [p ProtocolMethod]; Або просто: [(id <MyProtocol>) self.myViewController ProtocolMethod];
Форд
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.