web-dev-qa-db-fra.com

Cast une instance d'une classe dans un @protocol dans Objective-C

J'ai un objet (un UIViewController) qui peut ou non être conforme à un protocole que j'ai défini.

Je sais que je peux déterminer si l'objet est conforme au protocole, puis appeler la méthode en toute sécurité:

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

Cependant, XCode affiche un avertissement:

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

Quelle est la bonne façon d'éviter cet avertissement? Je n'arrive pas à lancer self.myViewController en tant que classe MyProtocol.

95
Ford

La bonne façon de procéder consiste à:

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

Le UIViewController <MyProtocol> * type-cast se traduit par "vc est un objet UIViewController conforme à MyProtocol", alors que l'utilisation de id <MyProtocol> se traduit par "vc est un objet d'une classe inconnue conforme à MyProtocol".

De cette façon, le compilateur vous donnera une vérification de type appropriée sur vc - le compilateur ne vous donnera un avertissement que si une méthode n'est pas déclarée sur UIViewController ou <MyProtocol> est appelé. id ne doit être utilisé dans la situation que si vous ne connaissez pas la classe/le type de l'objet en cours de conversion.

163
Nick Forge

Vous pouvez le lancer comme ceci:

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

Cela m'a un peu égaré aussi. Dans Objective-C, le protocole n'est pas le type lui-même, vous devez donc spécifier id (ou un autre type, tel que NSObject) avec le protocole souhaité.

59
Andy