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 tantid
, 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é dedelegate
tapée commeid<MyProtocol>
. Alors siobj
est une instance de MyClass, vous ne pouvez pas parler de[obj.delegate class]
; le compilateur se plaint que cetteclass
n'est pas une méthode d'instance connue! C'est parce queobj.delegate
est tapé commeid<MyProtocol>
, et donc sa seule méthode d'instance connue estdoSomething:
la méthode définie par MyProtocol. Nous pouvons contourner ceobj.delegate
enobj.delegate
à unid
; une solution plus élégante, lorsque la définition de MyClass est à nous, est de déclarer la propriété dudelegate
commeNSObject<MyProtocol>*
au lieu deid<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 = ...;