2009-06-27 5 views

Répondre

39

Les deux syntaxes servent des objectifs différents.

une catégorie nommée - @interface Foo (FooCategory) - est généralement utilisé pour:

(1) étendre une classe existante en ajoutant des fonctionnalités. Exemple: NSAttributedString dans Foundation est étendu par une catégorie dans AppKit qui ajoute une API de mise en forme de texte semblable à RTF spécifique à AppKit. (2) déclarer un ensemble de méthodes qui pourraient ou non être mises en œuvre par un délégué. Exemple: Différentes classes déclarent - mais n'implémentent pas - @interface NSObject (SetODelegateMethods).

Le formulaire (2) n'a plus la cote depuis que @protocol a été étendu pour prendre en charge les méthodes @optional dans Objective-C 2.0.

Une extension de classe - @interface Foo() - est conçue pour vous permettre de déclarer une API privée supplémentaire - SPI ou System Programming Interface - qui est utilisée pour implémenter les entrailles de la classe. Cela apparaît généralement en haut du fichier .m. Toutes les méthodes/propriétés déclarées dans l'extension de classe doivent être implémentées dans @implementation, tout comme les méthodes/propriétés trouvées dans l'interface @ public.

Les extensions de classe peuvent également être utilisées pour redéclarer une propriété @ readonly publique comme readwrite avant de @ synthétiser les accesseurs.

Exemple:

.h

@interface Foo:NSObject 
@property(readonly, copy) NSString *bar; 
-(void) publicSaucing; 
@end 

Foo.m

@interface Foo() 
@property(readwrite, copy) NSString *bar; 
- (void) superSecretInternalSaucing; 
@end 

@implementation Foo 
@synthesize bar; 
.... must implement the two methods or compiler will warn .... 
@end 
+0

La barre @synthesize n'est-elle pas utilisée? ligne signifie que le compilateur va générer les deux méthodes (getter et setter) pour la barre? – Elliot

+2

Oui, mais seul le getter est déclaré dans l'en-tête public, le setter est déclaré en privé pour être utilisé dans la classe elle-même. Ce n'est pas C++, si vous voulez introspecter l'exécution, vous pouvez trouver que le setter est là et l'appeler où vous voulez, mais à moins que vous le fassiez explicitement, vous obtiendrez des avertissements si vous essayez de définir la propriété. –

+0

@Louis est correct. La deuxième propriété remplace celle "readonly" dans la propriété de fichier .h en spécifiant "readwrite", c'est donc ce que le compilateur fait réellement. Cependant, seul le getter est visible pour les personnes, y compris le fichier d'en-tête, car quand ils importent le fichier, ils ne voient que la version "readonly" de la propriété. –

2

Oui,

il y a les différences suivantes.

1) L'utilisation de catégories anonymes nécessite l'implémentation de ses méthodes dans le bloc principal @implementation pour la classe correspondante; les catégories anonymes vous permettent de déclarer l'API supplémentaire requise pour une classe autre que la classe primaire @interface bloc

2) Lors de l'utilisation de MyClass (privé), les éléments suivants doivent être pris en compte: les paires objet/catégorie nommées doivent être unique. Si vous déclarez une catégorie privée sur votre propre classe, il n'y a pas de problème. Cependant, les choses sont différentes sur les classes existantes. Par exemple, une seule catégorie NSString (privée) peut exister dans un espace de noms Objective-C donné. Cela peut entraîner des problèmes car l'espace de noms Objective-C est partagé entre le code du programme et toutes les bibliothèques, frameworks et plug-ins. Ceci est particulièrement important pour les programmeurs Objective-C qui écrivent des screensavers, des panneaux de préférences et d'autres plug-ins. leur code sera injecté dans le code de l'application ou du framework qu'ils ne contrôlent pas.

+0

Êtes-vous sûr que c'est le cas que les catégories doivent posséder un nom unique? Je crois comprendre que tant que les sélecteurs sont uniques, il n'y aura pas de conflits. Le runtime est-il conscient des catégories? (la référence d'exécution ne les mentionne pas) – rpetrich

+0

Ce n'est pas la catégorie qui doit être nommée de façon unique: c'est l'objet/catégorie de paire qui doit l'être.Essayez vous-même de compiler deux catégories différentes de NSString (Privé), même en utilisant différentes méthodes dans un de vos projets et voyez si cela fonctionne. –

+0

Hmm ... il semble que le compilateur/éditeur de liens n'autorise pas les catégories en double sur une classe, mais le runtime le fait. Vous pouvez définir des catégories NSDictionary (NSDictionary) ou NSError (NSErrorPrivate) avec une méthode + load et le compilateur, l'éditeur de liens et l'exécution se comporteront comme prévu (même si Foundation.framework implémente ces deux catégories en interne). Si vous implémentez une catégorie qui a été nommée dans un en-tête tel que NSString (NSStringExtensionMethods), le compilateur émettra des avertissements, mais l'éditeur de liens et l'exécution se comportent toujours comme prévu. Rien de tout cela n'est réellement utile dans le monde réel. – rpetrich

Questions connexes