38 votes

Définir des catégories pour les protocoles dans Objective-C?

En Objective-C, je peux ajouter des méthodes aux classes existantes, avec une catégorie, par exemple

@interface NSString (MyCategory)
- (BOOL) startsWith: (NSString*) prefix;
@end

Est-il également possible de le faire avec les protocoles, c'est à dire si il y avait un NSString protocole, quelque chose comme:

@interface <NSString> (MyCategory)
- (BOOL) startsWith: (NSString*) prefix;
@end

Je veux le faire depuis que j'ai plusieurs extensions de NSObject (la classe), en utilisant uniquement le public NSObject méthodes, et je veux que ces extensions également de travailler avec des objets de mise en œuvre du protocole .

Pour donner un autre exemple, si je veux écrire une méthode logDescription qui imprime un objet de la description dans le journal:

- (void) logDescription {
    NSLog(@"%@", [self description]);
}

Je peux bien sûr ajouter cette méthode de NSObject, mais il y a d'autres classes qui n'héritent pas de NSObject, où j'aimerais aussi avoir cette méthode, par exemple NSProxy. Puisque la méthode utilise uniquement le public et les membres de protocole , il serait préférable de l'ajouter au protocole.

Edit: Java 8 est maintenant avec de "virtuel méthodes d'extension" dans les interfaces: http://cr.openjdk.java.net/~briangoetz/lambda/Défenseur%20Methods%20v4.pdf. C'est exactement ce que je voudrais faire en Objective-C. je n'ai pas vu cette question, gagnant beaucoup d'attention...

En ce qui concerne, Jochen

25voto

Dave DeLong Points 156978

Réponse courte: Non.

Réponse longue: comment serait-il? Imaginez que vous pourriez ajouter des méthodes aux protocoles existants? Comment serait-il? Imaginons que nous voulions ajouter une autre méthode pour NSCoding, dire -(NSArray *) codingKeys; Cette méthode est une méthode qui retourne un tableau de clés utilisées pour le codage de l'objet.

Le problème, c'est qu'il y a des classes existantes (comme, par exemple NSString) qui mettent déjà en œuvre NSCoding, mais ne pas mettre en œuvre notre - codingKeys méthode. Que doit-il arriver? Comment le pré-compilé cadre de savoir quoi faire lorsque ce requis message est envoyé à une classe qui n'a pas la mettre en œuvre?

Vous pourriez dire "on peut y ajouter la définition de cette méthode via une catégorie" ou "on peut dire que toutes les méthodes ajoutées via le protocole de ces catégories sont explicitement facultatif". Oui, vous pouvez le faire et, théoriquement, de contourner le problème que j'ai décrit ci-dessus. Mais si vous allez faire, vous pourriez tout aussi bien en faire une catégorie en premier lieu, puis assurez-vous que la classe respondsToSelector: avant d'appeler la méthode.

22voto

Douglas Mayle Points 7216

Même s'il est vrai que vous ne pouvez pas définir des catégories pour les protocoles (et ne veux pas, parce que vous ne savez rien à propos de l'objet existant), vous pouvez définir des catégories de telle manière que le code ne s'applique à un objet d'un type donné qui a le protocole désiré (un peu comme C++partielle du modèle de spécialisation).

L'utilisation principale pour quelque chose comme ça, c'est quand vous voulez définir une catégorie qui dépend d'une version personnalisée de la classe. (Imaginez que j'ai UIViewController sous-classes qui sont conformes à la Foo protocole, ce qui signifie qu'ils ont la propriété foo, mon code de la catégorie peut avoir besoin de la propriété foo, mais je ne peux pas l'appliquer à la Foo protocole, et si j'ai tout simplement l'appliquer à UIViewController, le code ne compile pas par défaut, et en l'obligeant à compiler signifie quelqu'un qui fait de l'introspection, ou tout simplement de vissage, pourriez appeler votre code qui dépend du protocole. Une approche hybride pourrait fonctionner comme ceci:

@protocol Foo
- (void)fooMethod

@property (retain) NSString *foo;
@end

@implementation UIViewController (FooCategory)

- (void)fooMethod {
    if (![self conformsToProtocol:@protocol(Foo)]) {
        return;
    }

    UIViewController<Foo> *me = (UIViewController<Foo>*) self;
    // For the rest of the method, use "me" instead of "self"
    NSLog(@"My foo property is \"%@\"", me.foo);
}
@end

Avec l'approche hybride, vous pouvez écrire le code qu'une seule fois (par classe qui est censé mettre en œuvre le protocole) et assurez-vous qu'il n'affecte pas les instances de la classe qui ne sont pas conformes au protocole.

L'inconvénient est que la propriété de synthèse/définition a encore à se produire dans les différentes sous-classes.

18voto

alex gray Points 5089

extObjC a les plus belles choses que vous pouvez faire avec les Protocoles / Catégories... tout d'abord est - @concreteprotocol...

  • Définit un "protocole concret", qui peut fournir des implémentations par défaut de méthodes dans le protocole.
  • Un @protocol bloc doit exister dans un fichier d'en-tête, et correspondant de l' @concreteprotocol bloc dans un fichier d'implémentation.
  • Tout objet qui déclare lui-même pour se conformer au présent protocole sera implémentations de méthode, mais seulement si aucune méthode n'par le même nom existe déjà.

MyProtocol.h

@protocol MyProtocol 
@required - (void)someRequiredMethod;
@optional - (void)someOptionalMethod;
@concrete - (BOOL)isConcrete;   

MyProtocol.m

 @concreteprotocol(MyProtocol) - (BOOL)isConcrete { return YES; } ...

donc, le fait de déclarer un objet MyDumbObject : NSObject <MyProtocol> retournera automatiquement YES de isConcrete.

Aussi, ils ont pcategoryinterface(PROTOCOL,CATEGORY) qui "définit l'interface pour une catégorie nommée CATÉGORIE sur un protocole de PROTOCOLE". Protocole catégories contiennent des méthodes qui sont automatiquement appliquées à toute la classe qui déclare lui-même pour se conformer au PROTOCOLE." Il s'accompagne d'une macro, vous devez également utiliser dans votre fichier de mise en oeuvre. Voir les docs.

Dernier, mais PAS moins / pas directement liés à l' @protocols est synthesizeAssociation(CLASS, PROPERTY), ce qui "synthétise une propriété d'une classe à l'aide d'objets associés. Ceci est principalement utile pour ajouter des propriétés à une classe au sein d'une catégorie. La PROPRIÉTÉ doit avoir été déclaré avec @property dans l'interface de la classe spécifiée (ou d'une catégorie sur elle), et doit être de type d'objet."

Donc, de nombreux outils dans cette bibliothèque ouverte (haut) les choses que vous pouvez faire avec ObjC... à partir de l'héritage multiple... bien, votre imagination est la limite.

7voto

Chuck Points 138930

Il n'est pas vraiment utile de le faire depuis un protocole ne peut pas vraiment mettre en œuvre la méthode. Un protocole est une façon de déclarer que vous avez l'appui de certaines méthodes. Ajout d'une méthode à cette liste à l'extérieur du protocole signifie que tous les "conformes" classes accidentellement déclarer la nouvelle méthode, même si elles ne sont pas la mettre en œuvre. Si certains de la classe de mise en œuvre de la NSObject protocole, mais ne descend pas de NSObject, et puis vous avez ajouté une méthode pour le protocole, qui briserait la classe, la conformité de l'.

Toutefois, vous pouvez créer un nouveau protocole qui comprend l'ancien avec une déclaration comme @protocol SpecialObject <NSObject>.

0voto

slf Points 15327

Je pense que vous peut être un mélange des termes ici et là. Les Extensions, les Catégories, les Protocoles, les Interfaces et les Classes sont toutes des choses différentes en Objective-C. Dans L'Objective-C 2.0 de la Langue d'Apple décrit les différences très bien, y compris les avantages et les inconvénients à l'utilisation de catégories et de ses extensions.

Si vous pensez à ce sujet, qu'est ce qu'une "Catégorie" ou "Extension" dans le sens conceptuel? C'est une façon d'ajouter des fonctionnalités à une Classe. En Objective-C, les protocoles sont conçus pour avoir une absence de mise en œuvre. Donc, comment voulez-vous ajouter ou de prolonger la mise en œuvre de quelque chose qui n'est pas mise en œuvre pour commencer?

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X