En Objective-C, un protocole est un groupe de méthodes pouvant être implémentées par n'importe quelle classe. Les protocoles sont essentiellement les mêmes que les interfaces en C # et les deux ont des objectifs similaires. Ils peuvent être utilisés en tant que type de pseudo-données, ce qui est utile pour s'assurer qu'un objet typé dynamiquement peut répondre à un certain ensemble de messages. Et, comme toute classe peut "adopter" un protocole, elle peut être utilisée pour représenter une API partagée entre des classes totalement non liées..
La documentation officielle décrit à la fois une méthode informelle et une méthode formelle pour déclarer des protocoles, mais les protocoles informels ne sont en réalité qu'une utilisation unique de catégories et n'offrent pas autant d'avantages que les protocoles formels. Dans cet esprit, ce chapitre se concentre uniquement sur formel les protocoles.
Voyons d’abord comment déclarer un protocole formel. Créez un nouveau fichier dans Xcode et sélectionnez l’icône de protocole Objective-C sous Mac OS X> Cacao:
Icône Xcode pour les fichiers de protocoleComme d'habitude, cela vous demandera un nom. Notre protocole contiendra des méthodes pour calculer les coordonnées d'un objet, appelons-le CoordinateSupport:
Nommer le protocoleCliquez sur Suivant et choisissez l'emplacement par défaut pour le fichier. Cela créera un protocole vide qui ressemble presque exactement à une interface:
// CoordinateSupport.h #import@protocol CoordinateSupport @fin
Bien sûr, au lieu de @interface
directive, il utilise @protocole
, suivi du nom du protocole. le
la syntaxe nous permet d'intégrer un autre protocole dans CoordinateSupport
. Dans ce cas, nous disons que CoordinateSupport
comprend également toutes les méthodes déclarées dans la NSObject
protocole (à ne pas confondre avec le NSObject
classe).
Ensuite, ajoutons quelques méthodes et propriétés au protocole. Cela fonctionne de la même manière que la déclaration de méthodes et de propriétés dans une interface:
#importation@protocol CoordinateSupport @propriété double x; @propriété double y; @propriété double z; - (NSArray *) arrayFromPosition; - (double) magnitude; @fin
Toute classe qui adopte ce protocole est assurée de synthétiser le X
, y
, et z
propriétés et mettre en œuvre le arrayFromPosition
et ordre de grandeur
méthodes. Alors que cela ne dit pas Comment ils seront implémentés, cela vous donne la possibilité de définir une API partagée pour un ensemble arbitraire de classes.
Par exemple, si on veut les deux Navire
et La personne
pour pouvoir réagir à ces propriétés et méthodes, nous pouvons leur dire d’adopter le protocole en le plaçant entre crochets après la déclaration de superclasse. Notez également que, tout comme pour l’utilisation d’une autre classe, vous devez importer le fichier de protocole avant de l’utiliser:
#importation#import "CoordinateSupport.h" @interface Person: NSObject @property (copy) NSString * name; @property (strong) NSMutableSet * friends; - (vide) dites bonjour; - (vide) dites au revoir; @fin
Maintenant, en plus des propriétés et méthodes définies dans cette interface, le La personne
il est garanti que la classe répondra à l'API définie par CoordinateSupport
. Xcode vous avertira que le La personne
la mise en œuvre est incomplète jusqu'à ce que vous synthétisez X
, y
, et z
, et mettre en œuvre arrayFromPosition
et ordre de grandeur
:
De même, une catégorie peut adopter un protocole en l'ajoutant après la catégorie. Par exemple, pour dire au La personne
classe à adopter le CoordinateSupport
protocole dans le Rapports
catégorie, vous utiliseriez la ligne suivante:
@interface Person (Relations)
Et, si votre classe doit adopter plusieurs protocoles, vous pouvez les séparer par des virgules:
@interface Person: NSObject
Sans protocoles, nous aurions deux options pour assurer à la fois Navire
et La personne
implémenté cette API partagée:
Navire
et La personne
en tant que sous-classes.Aucune de ces options n'est particulièrement attrayante: la première est redondante et sujette aux erreurs humaines, et la seconde est très restrictive, en particulier si elles héritent déjà de différentes classes parentes. Il doit être clair que les protocoles sont beaucoup plus souples et réutilisables, car ils évitent à l'API de dépendre d'une classe particulière..
Le fait que tout La classe peut facilement adopter un protocole permet de définir des relations horizontales au-dessus d'une hiérarchie de classe existante:
Liaison de classes non liées à l'aide d'un protocoleEn raison de la nature flexible des protocoles, les divers frameworks iOS en font bon usage. Par exemple, les contrôles de l'interface utilisateur sont souvent configurés à l'aide du modèle de conception de délégation, dans lequel un objet délégué est responsable de la réaction aux actions de l'utilisateur. Au lieu d'encapsuler les responsabilités d'un délégué dans une classe abstraite et de le forcer à le sous-classer, iOS définit l'API nécessaire au délégué dans un protocole. De cette façon, il est incroyablement facile pour tout objet pour agir en tant qu'objet délégué. Nous allons explorer cela plus en détail dans la seconde moitié de cette série, iOS succinctement.
Les protocoles peuvent être utilisés en tant que types psuedo-data. Au lieu de s'assurer qu'une variable est une instance d'une classe, l'utilisation d'un protocole en tant qu'outil de vérification de type garantit que la variable est toujours conforme à une API arbitraire. Par exemple, le suivant la personne
variable est garanti pour implémenter l'API CoordinateSupport.
La personne* personne = [[Person alloc] init];
Néanmoins, l’application forcée du protocole est souvent plus utile lorsqu’elle est utilisée avec le identifiant
Type de données. Cela vous permet d'assumer certaines méthodes et propriétés tout en ignorant complètement la classe de l'objet.
Et bien sûr, la même syntaxe peut être utilisée avec un paramètre de méthode. L'extrait suivant ajoute une nouvelle getDistanceFromObject:
méthode à l'API dont le paramètre est requis pour se conformer à CoordinateSupport
protocole:
// CoordinateSupport.h #import@protocol CoordinateSupport @propriété double x; @propriété double y; @propriété double z; - (NSArray *) arrayFromPosition; - (double) magnitude; - (double) getDistanceFromObject: (id )L'object; @fin
Notez qu'il est tout à fait possible d'utiliser un protocole dans le même fichier que celui défini.
En plus de la vérification de type statique décrite dans la dernière section, vous pouvez également utiliser le conforme au protocole:
méthode définie par le NSObject
protocole pour vérifier dynamiquement si un objet est conforme à un protocole ou non. Ceci est utile pour éviter les erreurs lorsqu’on travaille avec des objets dynamiques (objets saisis comme identifiant
).
L'exemple suivant suppose que La personne
la classe adopte le CoordinateSupport
protocole, tandis que le Navire
la classe n'a pas. Il utilise un objet typé dynamiquement appelé mysteryObject
pour stocker une instance de La personne
,et utilise ensuite conforme au protocole:
pour vérifier s'il dispose d'un support de coordonnées. Si c'est le cas, vous pouvez utiliser le X
, y
, et z
propriétés, ainsi que les autres méthodes déclarées dans la CoordinateSupport
protocole:
// main.m #import#import "Person.h" #import "Ship.h" int main (int argc, const char * argv []) @autoreleasepool id mysteryObject = [[Person alloc] init]; [mysteryObject setX: 10.0]; [mysteryObject setY: 0.0]; [mysteryObject setZ: 7.5]; // Ne commentez pas la ligne suivante pour voir la partie "else" du conditionnel. // mysteryObject = [[Ship alloc] init]; if ([mysteryObject conformeToProtocol: @protocol (CoordinateSupport)]]) NSLog (@ "Ok pour supposer un support de coordonnées."); NSLog (@ "L'objet est situé à (% 0.2f,% 0.2f,% 0.2f)", [mysteryObject x], [mysteryObject y], [mysteryObject z]); else NSLog (@ "Erreur: Impossible d'assumer un support de coordonnées."); NSLog (@ "Je ne sais pas du tout où se trouve cet objet…"); retourne 0;
Si vous décommentez la ligne qui réattribue le mysteryObject
à un Navire
par exemple, le conforme au protocole:
la méthode retournera NON
, et vous ne pourrez pas utiliser en toute sécurité l’API définie par CoordinateSupport
. Si vous n'êtes pas sûr du type d'objet qu'une variable va contenir, ce type de vérification de protocole dynamique est important pour empêcher le blocage de votre programme lorsque vous essayez d'appeler une méthode qui n'existe pas..
Notez également le nouveau @protocole()
directif. Cela fonctionne beaucoup comme @sélecteur()
, sauf qu'au lieu d'un nom de méthode, il faut un nom de protocole. Il retourne un Protocole
objet, qui peut être passé à conforme au protocole:
, parmi d'autres méthodes intégrées. Le fichier d’en-tête de protocole ne ne pas doivent être importés pour @protocole()
travailler.
Si vous travaillez avec de nombreux protocoles, vous vous retrouverez dans une situation où deux protocoles s'appuient l'un sur l'autre. Cette relation circulaire pose un problème au compilateur, car il ne peut pas importer l'un avec l'autre sans l'autre. Par exemple, supposons que nous essayons d’abréger certaines fonctionnalités du GPS dans un GPSSupport
protocole, mais veulent pouvoir convertir entre les coordonnées "normales" de notre existant CoordinateSupport
et les coordonnées utilisées par GPSSupport
. le GPSSupport
le protocole est assez simple:
#importation#import "CoordinateSupport.h" @protocol GPSSupport - (void) copyCoordinatesFromObject: (id )L'object; @fin
Cela ne pose aucun problème, c’est-à-dire jusqu’à ce que nous devions faire référence à GPSSupport
protocole de CoordinateSupport.h
:
#importation#import "GPSSupport.h" @protocol CoordinateSupport @propriété double x; @propriété double y; @propriété double z; - (NSArray *) arrayFromPosition; - (double) magnitude; - (double) getDistanceFromObject: (id )L'object; - (void) copyGPSCoordinatesFromObject: (id )L'object; @fin
Maintenant le CoordinateSupport.h
le fichier nécessite le GPSSupport.h
fichier à compiler correctement, et vice versa. C'est un problème de type poule ou œuf, et le compilateur ne l'aimera pas beaucoup:
Résoudre la relation récursive est simple. Tout ce que vous avez à faire est de déclarer en aval l'un des protocoles au lieu d'essayer de l'importer directement:
#importation@protocol CoordinateSupport; @protocol GPSSupport - (void) copyCoordinatesFromObject: (id )L'object; @fin
Tout @protocol CoordinateSupport;
dit est-ce CoordinateSupport
est en effet un protocole et le compilateur peut supposer qu’il existe sans l’importer. Notez le point-virgule à la fin de l'instruction. Cela pourrait être fait dans l'un des deux protocoles; le but est de supprimer la référence circulaire. Le compilateur ne se soucie pas de savoir comment vous le faites.
Les protocoles sont une fonctionnalité incroyablement puissante d'Objective-C. Ils vous permettent de capturer des relations entre des classes arbitraires lorsqu'il n'est pas possible de les connecter à une classe parent commune. Nous utiliserons plusieurs protocoles intégrés dans iOS succinctement, autant de fonctions de base d'une application iPhone ou iPad sont définies en tant que protocoles.
Le chapitre suivant présente les exceptions et les erreurs, deux outils très importants pour la gestion des problèmes inévitables lors de l’écriture de programmes Objective-C..
Cette leçon représente un chapitre de Objective-C Succinctly, un eBook gratuit de l’équipe de Syncfusion..