34 votes

Minutia sur les catégories et les extensions Objective-C

J'ai appris quelque chose de nouveau tout en essayant de comprendre pourquoi mon readwrite bien déclaré en privé, la Catégorie n'était pas de la génération d'un setter. C'était à cause de ma Catégorie a été nommé:

// .m
@interface MyClass (private)
@property (readwrite, copy) NSArray* myProperty;
@end

Changer l':

// .m
@interface MyClass ()
@property (readwrite, copy) NSArray* myProperty;
@end

et mon setter est synthétisé. Je sais maintenant que l'Extension de Classe n'est pas juste un autre nom pour un anonyme de la Catégorie. Laissant une Catégorie sans nom qu'il provoque, pour se transformer en une bête différente: l'une qui donne maintenant au moment de la compilation de la méthode de la mise en œuvre de l'application et permet d'ajouter ivars. Je comprends maintenant le général philosophies qui sous-tendent chacune de ces Catégories sont généralement utilisés pour ajouter des méthodes à une classe quelconque au moment de l'exécution, et les Extensions de la Classe sont généralement utilisés pour appliquer privé implémentation de l'API et ajouter ivars. Je l'assume.

Mais il y a des bricoles qui me confondre. Tout d'abord, à un haut niveau: Pourquoi différencier de ce genre? Ces concepts semblent comme des idées similaires qui ne peut pas décider si elles sont identiques, ou différents concepts. Si elles sont les mêmes, je m'attends à voir les mêmes choses exactes possibles en utilisant une Catégorie sans nom, comme c'est avec un nom de la Catégorie (qui ne le sont pas). Si elles sont différentes, (qui ils sont), je m'attends à une plus grande syntaxique disparité entre les deux. Il semble étrange à dire, "Oh, en passant, pour mettre en œuvre une Extension de Classe, il suffit d'écrire une Catégorie, mais de laisser le nom. Il change par magie."

Deuxièmement, sur le sujet de la compilation de l'application: Si vous ne pouvez pas ajouter des propriétés à un nom de Catégorie, pourquoi ne le faire convaincre le compilateur que vous n'avez juste qu'? Pour être clair, je vais illustrer avec mon exemple. Je peux déclarer une propriété en lecture seule dans le fichier d'en-tête:

// .h
@interface MyClass : NSObject
@property (readonly, copy) NSString* myString;
@end

Maintenant, je veux sur la tête à la mise en œuvre de fichier et me donner privé readwrite l'accès à la propriété. Si je le fais correctement:

// .m
@interface MyClass ()
@property (readwrite, copy) NSString* myString;
@end

Je reçois un avertissement lorsque je n'ai pas synthétiser, et quand je le fais, je peux définir le bien et tout est peachy. Mais, malheureusement, si je venais à être légèrement erronées à propos de la différence entre la Catégorie et la Classe de l'Extension et j'ai essayer:

// .m
@interface MyClass (private)
@property (readwrite, copy) NSString* myString;
@end

Le compilateur est complètement pacifié en pensant que la propriété est readwrite. Je n'ai pas d'avertissement, et pas même la belle erreur de compilation "Objet ne peut pas être réglé soit en lecture seule propriété ou pas de setter trouvé" dès la mise en myString que je n'avais-je pas déclaré la readwrite propriété dans la Catégorie. Je viens d'obtenir le "Ne répond pas à sélecteur" exception à l'exécution. Si l'ajout d'ivars et de propriétés n'est pas pris en charge par (nom) Catégories, est-ce trop demander que le compilateur jouer selon les mêmes règles? Ai-je raté quelque grand de la philosophie de design?

53voto

mipadi Points 135410

Les extensions de la classe ont été ajoutés en Objective-C 2.0 pour résoudre deux problèmes spécifiques:

  1. Permettre à un objet d'avoir un "privé" de l'interface qui est vérifié par le compilateur.
  2. Permettre la lecture publique, privée accessible en écriture propriétés.

Interface Privée

Avant d'Objective-C 2.0, si un développeur a voulu disposer d'un ensemble de méthodes en Objective-C, ils ont souvent déclaré "Privé" dans la catégorie de la classe de mise en œuvre de fichier:

@interface MyClass (Private)
- (id)awesomePrivateMethod;
@end

Cependant, ces méthodes ont souvent été mélangé dans la classe @implementation bloc (pas séparé @implementation bloc pour l' Private de la catégorie). Et pourquoi pas? Ce ne sont pas des extensions de la classe; ils seulement rattraper le manque de public/privé, les restrictions en Objective-C catégories.

Le problème est que l'Objective-C compilateurs supposer que les méthodes déclarées dans l'une des catégories seront mises en œuvre ailleurs, elles ne sont donc pas, vérifiez que tous les moyens sont mis en œuvre. Ainsi, un développeur peut déclarer awesomePrivateMethod mais ne parviennent pas à mettre en œuvre, et le compilateur ne serait pas de les avertir du problème. C'est le problème-vous remarqué: dans une catégorie, vous pouvez déclarer une propriété (ou une méthode), mais ne parviennent pas à obtenir un message d'avertissement si vous n'avez jamais réellement les mettre en œuvre-c'est parce que le compilateur s'attend à être mis en œuvre "quelque part" (le plus probable, dans une autre unité de compilation indépendante de celui-ci).

Entrez les extensions de la classe. Les méthodes déclarées dans une classe d'extension sont supposés être mis en œuvre dans les principaux @implementation bloc; si elles ne le sont pas, le compilateur émet un avertissement.

Lecture Publique, Privée Accessible En Écriture Aux Propriétés

Il est souvent avantageux de mettre en œuvre une immuable structure de données-qui est, celui dans lequel le code extérieur ne pouvez pas utiliser un setter pour modifier l'état de l'objet. Cependant, il peut toujours être agréable d'avoir une écriture à la propriété pour les internes de l'utiliser. Les extensions de la classe de permettre que: dans l'interface publique, un développeur peut déclarer une propriété en lecture seule, mais ensuite déclarer qu'il soit accessible en écriture dans la classe de l'extension. À l'extérieur de code, la propriété est en lecture seule, mais un setter peut être utilisé à l'intérieur.

Alors Pourquoi je ne Peux pas Déclarer une Écriture de la Propriété dans une Catégorie?

Les catégories ne peuvent pas ajouter des variables d'instance. Un setter nécessite souvent une sorte de support de stockage. Il a été décidé que l'autorisation d'une catégorie à déclarer une propriété que faut probablement un magasin de sauvegarde a été Une Mauvaise Chose™. Par conséquent, une catégorie ne peut pas déclarer une écriture de la propriété.

Ils Se Ressemblent, Mais Sont Différents

La confusion réside dans l'idée qu'une extension de classe est juste un "sans nom de catégorie". La syntaxe est similaire et implique cette idée; j'imagine que c'était juste choisi parce qu'il était familier à Objective-C pour les programmeurs et, à certains égards, les extensions de la classe sont comme les catégories. Ils sont semblables en ce que les deux fonctions vous permettent d'ajouter des méthodes (et propriétés) à une classe existante, mais ils servent à des fins différentes et donc des comportements différents.

8voto

Chuck Points 138930

Vous êtes confus par la similarité syntaxique. Une extension de classe n'est pas seulement une nouvelle catégorie. Une extension de classe est un moyen de rendre une partie de votre interface privée et une partie publique - les deux sont considérées comme une partie de la classe de l'interface de la déclaration. Faisant partie de la classe de l'interface, une extension doit être défini dans le cadre de la classe.

Une catégorie, d'autre part, est une façon d'ajouter des méthodes à une classe existante au moment de l'exécution. Ce pourrait être, par exemple, dans un autre bundle qui est chargé uniquement le jeudi.

Pour plus d'Objective-C de l'histoire, il était impossible d'ajouter des variables d'instance d'une classe à l'exécution, lorsque les catégories sont chargés. Cela a été travaillé autour de très récemment dans la nouvelle de l'exécution, mais la langue montre encore les cicatrices de son fragile classes de base. L'une d'elles est que la langue ne prend pas en charge l'ajout de catégories de variables d'instance. Vous aurez à écrire les getters et setters vous-même, le style old-school.

Les variables d'Instance dans les catégories sont un peu difficiles, trop. Puisqu'ils ne sont pas nécessairement présents lorsque l'instance est créée et l'initialiseur peut ne connaissent rien à leur sujet, l'initialisation est un problème qui n'existe pas avec la normale des variables d'instance.

3voto

ughoavgfhw Points 28400

Vous pouvez ajouter une propriété dans une catégorie, mais vous ne pouvez pas la synthétiser. Si vous utilisez une catégorie, vous ne recevrez pas d'avertissement de compilation car il s'attend à ce que le programme de configuration soit implémenté dans la catégorie.

0voto

Motti Shneor Points 703

Juste une petite précision à propos de la RAISON pour le comportement différent de sans nom des catégories (maintenant connu comme les Extensions de la Classe) et normal (nommé) catégories.

La chose est très simple. Vous pouvez avoir de NOMBREUSES catégories de l'extension de la même classe, chargé lors de l'exécution, sans que le compilateur et l'éditeur de liens ne sache jamais. (comme beaucoup de belles extensions de gens ont écrit à NSObject, qu'ajouter des fonctionnalités de post-hoc).

Maintenant, Objective-C n'a pas de notion d'ESPACE de NOM. Par conséquent, ayant iVars défini dans un nom de catégorie pourrait créer un symbole de l'affrontement dans l'exécution. Si deux catégories différentes seraient en mesure de définir la même

@interface myObject (extensionA) {
 NSString *myPrivateName;
}
@end
@interface myObject (extensionB) {
 NSString *myPrivateName;
}
@end

alors au moins, il y aura de dépassement de capacité de la mémoire lors de l'exécution.

En contradiction, les extensions de la Classe n'ont PAS de NOM, et donc il ne peut y avoir qu'UN seul. C'est pourquoi vous pouvez définir iVars là. Ils sont assurés d'être unique.

Comme pour le compilateur erreurs et avertissements liés à des catégories et des extensions de la classe + ivars et définitions de propriété, je suis d'accord qu'ils ne sont pas si utiles, et j'ai passé trop de temps à essayer de comprendre le pourquoi des choses compiler ou non, et comment ils fonctionnent (si ils travaillent) après la compilation.

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