2009-06-13 6 views

Répondre

80

Tout d'abord, un peu historical perspective on the topic, de l'un des créateurs de Java. Ensuite, Wikipedia a un modérément utile section on Objective-C protocols. En particulier, comprendre que Objective-C supporte à la fois protocoles formels (qui sont explicitement déclarés avec le mot-clé @protocol, l'équivalent d'une interface Java) et protocoles informels (juste une ou plusieurs méthodes implémentées par une classe, qui peut être découvert par réflexion). Si vous adoptez un protocole formel (terminologie Objective-C pour «implémenter une interface»), le compilateur émettra des avertissements pour les méthodes non implémentées, comme vous le feriez en Java. Contrairement à Java (comme skaffman mentionné), si une classe Objective-C implémente les méthodes contenues dans un protocole formel, elle est dite "conforme" à ce protocole, même si son interface ne l'adopte pas explicitement. Vous pouvez tester la conformité du protocole dans le code (en utilisant -conformsToProtocol:) comme ceci:

if ([myObject conformsToProtocol:@protocol(MyProtocol)]) { 
    ... 
} 

REMARQUE: documentation états d'Apple:

« Cette méthode détermine la conformité uniquement sur la base des déclarations officielles dans les fichiers d'en-tête , comme illustré ci-dessus, il ne vérifie pas si les méthodes déclarées dans le protocole sont effectivement implémentées - c'est la responsabilité du programmeur. "

Au Objective-C 2.0 (sous Mac OS X 10.5 « Leopard » et iOS), les protocoles officiels peuvent maintenant définir méthodes optionnelles, et une classe est conforme à un protocole aussi longtemps qu'il met en œuvre toutes les méthodes nécessaires . Vous pouvez utiliser les mots clés @required (par défaut) et @optional pour basculer entre les déclarations de méthode ou pour se conformer au protocole. (Voir la section du guide Objective-C 2.0 Programming Language d'Apple qui traite de optional protocol methods.)

méthodes de protocole facultatif ouvrent beaucoup de flexibilité aux développeurs, en particulier pour la mise en œuvre délégués et auditeurs. Au lieu d'étendre quelque chose comme un MouseInputAdapter (ce qui peut être gênant, puisque Java est aussi un seul héritage) ou d'implémenter beaucoup de méthodes vides inutiles, vous pouvez adopter un protocole et implémenter seulement les méthodes optionnelles qui vous intéressent. Avec ce modèle, l'appelant vérifie si la méthode est mise en oeuvre avant d'appeler (à l'aide -respondsToSelector) comme ceci:

if ([myObject respondsToSelector:@selector(fillArray:withObject:)]) { 
    [myObject fillArray:anArray withObject:foo]; 
    ... 
} 

Si la surcharge de réflexion devient un problème, vous pouvez toujours cache the boolean result for reuse, mais résister à l'envie d'optimiser prématurément . :-)

+4

"Si vous adoptez un protocole formel (terminologie Objective-C pour" implémenter une interface "), le compilateur émettra des avertissements pour les méthodes non implémentées, comme vous pouvez vous y attendre dans Java." Java émet une erreur dans ce cas, pas un avertissement. –

+3

"si une classe Objective-C implémente les méthodes contenues dans un protocole formel, elle est dite" conforme "à ce protocole, même si son interface ne l'adopte pas explicitement.Vous pouvez tester la conformité du protocole dans le code (en utilisant -conformsToProtocol :) comme ceci "Ceci est FAUX. '-conformsToProtocol:' ne retournera que YES si la classe adopte explicitement le protocole. Avez-vous déjà essayé? – user102008

+2

Vous avez raison, '-conformsToProtocol:' exige en effet que la classe (ou un ancêtre) déclare formellement qu'elle adopte le protocole. Je ne sais pas comment je me suis trompé, merci pour la correction! –

18

Ils sont presque identiques. Cependant la seule chose qui m'a échappé, c'est que si vous déclarez explicitement qu'un protocole C objectif implémente NSObject, les références à ce protocole n'ont pas accès aux méthodes que NSObject déclare (sans avertissement de compilateur de toute façon). Avec java vous pouvez avoir une référence à une interface, et toujours appeler toString() etc dessus.

par exemple

Objectif C:

@protocol MyProtocol 
// Protocol definition 
@end 

id <MyProtocol> myProtocol; 

[myProtocol retain] // Compiler warning 

Java:

public interface MyInterface { 
// interface definition 
} 

MyInterface myInterface; 

myInterface.toString(); // Works fine. 

Objectif C (fixe):

@protocol MyProtocol <NSObject> 
// Protocol definition 
@end 

id <MyProtocol> myProtocol; 

[myProtocol retain] // No Warning 
+25

Cela est dû au fait que id et NSObject * ne sont pas identiques *. En Java, l'objet racine est Object. En Objective-C, NSObject est un objet racine, mais pas * l'objet racine *. Si vous souhaitez accéder à toutes les méthodes NSObject (méthodes de classe ainsi que les protocoles), indiquez-le explicitement: NSObject myProtocol; au lieu de: id ... Lorsque vous utilisez id, vous dites: je ne me soucie pas de l'objet, * seulement * le protocole, ce qui dans votre cas n'est pas vrai. –

+0

@JasonCoco cool: D – hqt

Questions connexes