Question

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

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

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

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

Je souhaite le faire car j'ai plusieurs extensions de NSObject (la classe), utilisant uniquement les méthodes publiques NSObject, et je souhaite que ces extensions fonctionnent également avec des objets implémentant le protocole.

Pour donner un autre exemple, que se passe-t-il si je souhaite écrire une méthode logDescription qui imprime la description d'un objet dans le journal :

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

Je peux bien sûr ajouter cette méthode à NSObject, mais il existe d'autres classes qui n'héritent pas de NSObject, pour lesquelles j'aimerais également avoir cette méthode, par exemple.NSProxy.Étant donné que la méthode n'utilise que des membres publics du protocole, il serait préférable de l'ajouter au protocole.

Modifier:Java 8 propose désormais cela avec des "méthodes d'extension virtuelle" dans les interfaces : http://cr.openjdk.java.net/~briangoetz/lambda/Defender%20Methods%20v4.pdf.C'est exactement ce que j'aimerais faire en Objective-C.Je n'ai pas vu cette question attirer autant d'attention...

Cordialement, Jochen

Était-ce utile?

La solution

extObjC a les trucs les plus NEAT vous pouvez le faire avec les protocoles/catégories...tout d'abord c'est @concreteprotocol...

  • Définit un « protocole concret » qui peut fournir des implémentations par défaut de méthodes au sein du protocole.
  • Un @protocol Le bloc doit exister dans un fichier d'en-tête et un bloc correspondant @concreteprotocol block dans un fichier d’implémentation.
  • Tout objet qui se déclare conforme à ce protocole recevra ses implémentations de méthode, mais seulement si aucune méthode du même nom n'existe déjà.

MonProtocole.h

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

MonProtocole.m

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

donc déclarer un objet MyDumbObject : NSObject <MyProtocol> reviendra automatiquement YES à isConcrete.

Aussi, ils ont pcategoryinterface(PROTOCOL,CATEGORY) qui "définit l'interface pour une catégorie nommée CATÉGORIE sur un protocole PROTOCOLE".Les catégories de protocole contiennent des méthodes qui sont automatiquement appliquées à toute classe qui se déclare conforme au PROTOCOLE." Il existe une macro d'accompagnement que vous devez également utiliser dans votre fichier d'implémentation.Voir les documents.

Dernier, mais PAS le moindre / pas directement relatif à @protocols estsynthesizeAssociation(CLASS, PROPERTY), qui « synthétise une propriété pour 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ée auprès de @property dans l'interface de la classe spécifiée (ou d'une catégorie associée) et doit être de type objet."

Tant des outils de cette bibliothèque ouvrent (en haut) les choses que vous pouvez faire avec ObjC...d'un héritage multiple...eh bien, votre imagination est la limite.

Autres conseils

Réponse courte:. Non

Réponse longue: comment ce travail? Imaginez que vous pourrait ajouter des méthodes aux protocoles existants? Comment cela fonctionnerait-il? Imaginez que nous voulions ajouter une autre méthode pour NSCoding, disons -(NSArray *) codingKeys; Cette méthode est une méthode nécessaire qui retourne un tableau des clés utilisées pour coder l'objet.

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

On peut dire « nous pouvons ajouter la définition de cette méthode par une catégorie » ou « on peut dire que toutes les méthodes ajoutées par ces catégories de protocole sont explicitement en option ». Oui, vous pouvez le faire et obtenir théoriquement autour du problème que je l'ai décrit ci-dessus. Mais si vous allez le faire, vous pourriez tout aussi bien faire une catégorie en premier lieu, puis vérifiez que la respondsToSelector: de classe avant d'appeler la méthode.

Il est vrai que vous ne pouvez pas définir des catégories pour les protocoles (et ne voudriez pas, parce que vous ne savez pas quoi que ce soit à propos de l'objet existant), vous pouvez définir des catégories de telle sorte que le code ne s'applique qu'aux un objet du type donné qui a le protocole souhaité (un peu comme spécialisation de modèle partielle de C ++).

L'utilisation principale pour quelque chose comme ceci est lorsque vous souhaitez définir une catégorie qui dépend d'une version personnalisée d'une classe. (Imaginez que j'ai sous-classes UIViewController qui sont conformes au protocole Foo, ce qui signifie qu'ils ont la propriété foo, mon code de catégorie peut avoir besoin de la propriété foo, mais je ne peux pas l'appliquer au protocole Foo, et si je demande simplement à UIViewController, le code ne sera pas compilé par défaut, et le forçant à compiler, une personne faisant l'introspection, ou tout simplement vissage, pourrait 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 une seule fois (par classe qui est censé mettre en œuvre le protocole) et assurez-vous qu'il n'affectera pas les instances de la classe qui ne sont pas conformes au protocole.

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

Il est pas vraiment de sens de le faire depuis un protocole ne peut réellement mettre en œuvre la méthode. Un protocole est une façon de déclarer que vous soutenez certaines méthodes. Ajout d'une méthode à cette liste en dehors du protocole signifie que tous les « conformes » les classes déclarent accidentellement la nouvelle méthode, même si elles ne mettent pas. Si une classe a mis en œuvre le protocole NSObject, mais ne descend pas de NSObject, puis vous avez ajouté une méthode pour le protocole, qui briserait la conformité de la classe.

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

Je pense que vous pouvez confondrez termes ici et là. Extensions, Catégories, protocoles, interfaces et classes sont des choses toutes différentes en Objective-C. Dans Le langage Objective-C 2.0 Apple a décrit les différences très bien, y compris les avantages et les inconvénients à l'utilisation de catégories et extensions.

Si vous pensez à ce sujet, ce qui est une « catégorie » ou « Extension » au sens conceptuel? Il est une façon d'ajouter des fonctionnalités à une classe. En Objective-C, les protocoles sont conçus pour avoir aucune mise en œuvre. Par conséquent, comment voulez-vous ajouter ou étendre la mise en œuvre de quelque chose qui n'a pas mise en œuvre pour commencer?

si vous écrivez déjà une catégorie, pourquoi ne pas simplement ajouter dans la définition de protocole dans l'en-tête juste après la définition de la catégorie?

i.e..

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

@protocol MyExtendedProtocolName <NSString>
//Method declarations go here
@end

ainsi toute classe qui importe l'en-tête de la catégorie sera également obtenir la définition du protocole, et vous pouvez l'ajouter dans votre classe ..

@interface MyClass <OriginalProtocol,MyExtendedProtocolName>

aussi, soyez prudent lorsque NSString le sous-classement, il est un cluster et vous ne pouvez pas toujours obtenir le comportement que vous attendez.

Adam de Sharp a affiché une solution qui a fonctionné pour moi.

Il comporte 3 étapes:

  1. Définir les méthodes que vous voulez ajouter @optional sur un protocole.
  2. Faire les objets que vous souhaitez étendre conforme à ce protocole.
  3. Copie ces méthodes dans les objets lors de l'exécution.

Consultez le lien pour tous les détails.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top