Un identifiant conforme au protocole vs Qualifier un identifiant avec un protocole

Je passais par la programmation avec le document Objective-C fourni par Apple.

J'essaie de comprendre le paragraphe suivant, mais jusqu'ici, incapable de le faire.

@protocol XYZPieChartViewDataSource - (NSUInteger)numberOfSegments; - (CGFloat)sizeOfSegmentAtIndex:(NSUInteger)segmentIndex; @optional - (NSSsortingng *)titleForSegmentAtIndex:(NSUInteger)segmentIndex; @required - (UIColor *)colorForSegmentAtIndex:(NSUInteger)segmentIndex; @end @interface XYZPieCharView : UIView @property (weak) id <XYZPieChartViewDataSource> dataSource; // some additional stuff @end 

Si vous tentez d'appeler la méthode respondsToSelector: sur un ID conforme au protocole tel qu'il est défini ci-dessus, vous obtiendrez une erreur de compilation indiquant qu'il n'existe aucune méthode d'instance connue. Une fois que vous qualifiez un identifiant avec un protocole, toute vérification de type statique revient; vous obtiendrez une erreur si vous essayez d'appeler une méthode qui n'est pas définie dans le protocole spécifié. Une façon d'éviter l'erreur du compilateur consiste à définir le protocole personnalisé pour adopter le protocole NSObject.

Je suis confus à ce qui est la différence entre "se conformer au protocole" et "qualifier un object avec protocole". Et pourquoi le compilateur devrait-il générer une erreur si nous envoyons un identifiant – conforme au protocole – le message respondsToSelector ?

Et pourquoi le compilateur doit-il générer une erreur si nous envoyons un identifiant – conforme au protocole – le message respondsToSelector

Oui, c'est une chose très étrange. De nos jours, sous ARC, le compilateur lancera une erreur si un object déclaré comme id <XYZPieChartViewDataSource> est envoyé à la méthode id <XYZPieChartViewDataSource> la méthode de class , ou à toute autre méthode d'instance NSObject de base! Essayez-le et voyez.

Cela semble étrange, car id devrait permettre l'envoi de tout message (connu). Cependant, id <XYZPieChartViewDataSource> est considéré comme un type complètement spécifique; le compilateur autorisera uniquement les messages qui font partie du protocole XYZPieChartViewDataSource. Une solution moderne est la suivante: ne pas utiliser

 id <XYZPieChartViewDataSource> 

Au lieu de cela, utilisez

 NSObject<XYZPieChartViewDataSource>* 

Cela provoque toute la bonté délicieuse de NSObject à inclure (en ce qui concerne le compilateur) dans cet object, y compris la possibilité de répondre à respondsToSelector: et class et des choses comme ça.

Voici un paragraphe que j'ai inséré dans mon livre, discutant de cette question:

Curieusement, le compilateur traite un object typé id<SomeProtocol> très différemment de la façon dont il traite un object typé en tant id , ce qui ne permet que d'envoyer des methods définies dans SomeProtocol à cet object. Par exemple, supposons que MyClass soit défini avec une propriété de delegate tapée comme id<MyProtocol> . Alors si obj est une instance de MyClass, vous ne pouvez pas parler de [obj.delegate class] ; le compilateur se plaint que cette class n'est pas une méthode d'instance connue! C'est parce que obj.delegate est tapé comme id<MyProtocol> , et donc sa seule méthode d'instance connue est doSomething: la méthode définie par MyProtocol. Nous pouvons contourner ce obj.delegate en obj.delegate à un id ; une solution plus élégante, lorsque la définition de MyClass est à nous, est de déclarer la propriété du delegate comme NSObject<MyProtocol>* au lieu de id<MyProtocol> .

Conforme au protocole

C'est à ce moment que la définition @interface de votre class spécifie que la class implémente (ou se conforme à) un protocole. C'est une information au compilateur pour vérifier que la class implémente bien les methods requirejses.

 @interface MyClass < MyProtocol > 

Qualifier un object avec Protocole

Cela ajoute des informations supplémentaires à un type de pointeur, généralement un id , pour indiquer au compilateur que l'object référencé implémentera les methods spécifiées par le protocole (donc elles sont valides pour être appelées). L'inverse de ceci est que toutes les methods qui ne sont pas définies dans le protocole ne sont pas valides pour être appelées et vous recevrez un avertissement si vous essayez.

 id < MyProtocol > myObject = ...;