Différences entre les interfaces Java et les protocoles Objective-C?

93

Je connais Java et j'apprends maintenant Objective-C. Quelles sont exactement les différences entre les interfaces Java et les protocoles Objective-C?

Arne Evertsson
la source

Réponses:

82

Tout d'abord, un petit point de vue historique sur le sujet , d'un des créateurs de Java. Ensuite, Wikipedia a une section modérément utile sur les protocoles Objective-C . En particulier, comprenez qu'Objective-C prend en charge à la fois les protocoles formels (qui sont explicitement déclarés avec le @protocolmot - clé, l'équivalent d'une interface Java) et les protocoles informels (juste une ou plusieurs méthodes implémentées par une classe, qui peuvent être découvertes 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 vous en doutez en Java. Contrairement à Java (comme skaffman l'a 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: la documentation d'Apple indique:

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

Depuis Objective-C 2.0 (sous OS X 10.5 "Leopard" et iOS), les protocoles formels peuvent désormais définir des méthodes optionnelles , et une classe est conforme à un protocole tant qu'elle implémente toutes les méthodes requises. Vous pouvez utiliser les mots clés @required(par défaut) et @optionalpour indiquer si les déclarations de méthode qui suivent doivent ou peuvent être implémentées pour se conformer au protocole. (Voir la section du guide du langage de programmation Objective-C 2.0 d'Apple qui traite des méthodes de protocole facultatives .)

Les méthodes de protocole facultatives offrent une grande flexibilité aux développeurs, en particulier pour l'implémentation des délégués et des écouteurs . Au lieu d'étendre quelque chose comme un MouseInputAdapter (ce qui peut être ennuyeux, puisque Java est également un héritage unique) ou d'implémenter beaucoup de méthodes vides et inutiles, vous pouvez adopter un protocole et implémenter uniquement les méthodes facultatives qui vous intéressent. Avec ce modèle, l'appelant vérifie si la méthode est implémentée avant de l'appeler (en utilisant -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 mettre en cache le résultat booléen pour réutilisation , mais résistez à l'envie d'optimiser prématurément. :-)

Quinn Taylor
la source
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 vous en doutez en Java." Java émettrait une erreur dans ce cas, pas un avertissement.
Raffi Khatchadourian
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 ça "C'est FAUX. -conformsToProtocol:ne retournera OUI que si la classe adopte explicitement le protocole. Avez-vous même essayé?
user102008
2
Vous avez raison, il -conformsToProtocol:faut 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!
Quinn Taylor
18

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

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
Tom Jefferys
la source
25
En effet, 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 protocoles), indiquez-le explicitement: NSObject <MyProtocol> myProtocol; au lieu de: id <MyProtocol> ... Lorsque vous utilisez id, vous dites: je me fiche de l'objet, seulement du protocole, ce qui dans votre cas n'est pas vrai.
Jason Coco