Quelle est la différence entre l'héritage et les catégories dans Objective-C

Quelqu'un peut-il m'expliquer la différence entre les catégories et l'héritage dans L'objectif C? J'ai Lu l'entrée dans Wikipedia et la discussion sur les catégories ne semble pas différente de celle de l'héritage. J'ai également regardé la discussion sur le sujet dans le livre "Open Développement iPhone" et je ne comprends toujours pas.

57
demandé sur nevan king 2009-02-07 00:53:16

7 réponses

Parfois, l'héritage semble juste plus de problèmes qu'il ne vaut la peine. Il est correctement utilisé lorsque vous voulez ajouter quelque chose à une classe existante qui correspond à un changement dans le comportement de cette classe.

Avec une catégorie, vous voulez juste que l'objet existant fasse un peu plus. Comme déjà donné, si vous voulez juste avoir une classe string qui gère la compression, vous n'avez pas besoin de sous-classer la classe string, vous créez simplement une catégorie qui gère la compression. De cette façon, vous n'avez pas besoin de modifiez le type des classes de chaîne que vous utilisez déjà.

L'indice est dans la restriction que les catégories ajoutent uniquement des méthodes, vous ne pouvez pas ajouter de variables à une classe en utilisant des catégories. Si la classe a besoin de plus de propriétés, elle doit être sous-classée.(edit: vous pouvez utiliser le stockage associatif, je crois).

Les catégories sont un bon moyen d'ajouter des fonctionnalités tout en se conformant à un principe orienté objet pour préférer la composition à l'héritage.

Modifier Janvier 2012

Les choses ont changé MAINTENANT. Avec le compilateur LLVM actuel et le runtime 64 bits moderne, vous pouvez ajouter des iVars et des propriétés à la classe extensions (Pas de catégories). Cela vous permet de garder les iVars privés hors de l'interface publique. Mais, si vous déclarez des propriétés pour les iVars, elles peuvent toujours être accédées / modifiées via KVC, car il n'y a toujours pas de méthode privée dans Objective-C.

96
répondu Abizern 2013-06-17 02:20:17

Les catégories

Vous permettent d'ajouter des méthodes aux classes existantes. Donc, plutôt que de sous-classer NSData pour ajouter vos nouvelles méthodes de cryptage géniales, vous pouvez les ajouter directement à la classe NSData. Chaque objet NSData de votre application a maintenant accès à ces méthodes.

Pour voir comment cela peut être utile, regardez: CocoaDev

17
répondu Terry Wilcox 2009-02-06 22:03:19

L'une des illustrations préférées des catégories Objective-c en action est NSString. NSString est défini dans le framework Foundation, qui n'a aucune notion de vues ou de fenêtres. Cependant, si vous utilisez un NSString dans une application Cocoa, vous remarquerez qu'il répond à des messages comme – drawInRect:withAttributes:.

AppKit définit une catégorie pour NSString qui fournit des méthodes de dessin supplémentaires. La catégorie permet d'ajouter de nouvelles méthodes à une classe existante, donc nous ne faisons que traiter NSStrings. Si AppKit au lieu de cela, le dessin implémenté en sous-classant nous devrions traiter avec 'AppKitStrings' ou 'NSSDrawableStrings' ou quelque chose comme ça.

Les catégories

Vous permettent d'ajouter des méthodes spécifiques à l'application ou au domaine aux classes existantes. Il peut être assez puissant et pratique.

11
répondu amrox 2009-12-09 05:37:41

Si vous en tant que programmeur recevez un ensemble complet de code source pour une bibliothèque de code ou une application, vous pouvez devenir fou et changer tout ce dont vous avez besoin pour atteindre votre objectif de programmation avec ce code.

Malheureusement, ce n'est pas toujours le cas ou même souhaitable. Beaucoup de fois, on vous donne un kit de bibliothèque / objet binaire et un ensemble d'en-têtes à faire avec.

Ensuite, une nouvelle fonctionnalité est nécessaire pour une classe afin que vous puissiez faire quelques choses:

  1. Créer un nouveau classe entière au lieu d'une classe stock-répliquant toutes ses fonctions et membres puis réécrire tout le code pour utiliser la nouvelle classe.

  2. Créez une nouvelle classe wrapper qui contient la classe stock En tant que membre (compositing) et réécrivez la base de code pour utiliser la nouvelle classe.

  3. Correctifs binaires de la bibliothèque pour changer le code (bonne chance)

  4. Forcer le compilateur à voir votre nouvelle classe que l'ancien et j'espère qu'il ne dépend pas d'une certaine taille ou le lieu dans la mémoire et les points d'entrée spécifiques.

  5. Spécialisation des sous-classes-créer des sous-classes pour ajouter des fonctionnalités et modifier le code du pilote pour utiliser la sous-classe à la place - théoriquement, il devrait y avoir peu de problèmes et si vous avez besoin d'ajouter des membres de données, c'est nécessaire, mais l'empreinte mémoire sera différente. Vous avez l'avantage d'avoir à la fois le nouveau code et de l'ancien code disponible dans la sous-classe et de choisir lequel utiliser, la méthode de classe de base ou remplacés méthode.

  6. Modifiez la classe objc nécessaire avec une définition de catégorie contenant des méthodes pour faire ce que vous voulez et/ou remplacer les anciennes méthodes dans les classes de stock.

    Cela peut également corriger les erreurs dans la bibliothèque ou personnaliser les méthodes pour les nouveaux périphériques matériels ou autre. Ce n'est pas une panacée, mais cela permet d'ajouter une méthode de classe sans recompiler la classe/bibliothèque inchangée. La classe d'origine est la même dans le code, la taille de la mémoire et les points d'entrée, de sorte que les applications héritées ne pas casser. Le compilateur met tout simplement la nouvelle méthode(s) dans l'exécution comme appartenant à cette classe, et remplace les méthodes avec la même signature que dans le code d'origine.

    Un exemple:

    Vous avez une classe Bing qui sort vers un terminal, mais pas vers un port série, et maintenant c'est ce dont vous avez besoin. (pour certaines raisons). Vous avez Bing.h et libBing.so, mais pas Bing.m dans votre kit.

    La classe Bing fait toutes sortes de choses en interne, vous ne savez même pas tout ce que, vous avez juste l'api publique dans l'en-tête.

    Vous êtes intelligent, vous créez donc une catégorie (SerialOutput) pour la classe Bing.

    [Bing_SerialOutput.m]
    @interface Bing (SerialOutput)   // a category
    - (void)ToSerial: (SerialPort*) port ;
    @end
    
    @implementation Bing (SerialOutput)
    - (void)ToSerial: (SerialPort*) port 
    {
    ... /// serial output code ///
    }
    @end
    

    Le compilateur oblige à créer un objet qui peut être lié à votre application et le runtime sait maintenant que Bing répond à @selector (toserial:) et vous pouvez l'utiliser comme si la classe Bing était construite avec cette méthode. Vous ne pouvez pas ajouter des méthodes de membres de données uniquement et cela n'était pas destiné à créer des tumeurs géantes de code attaché aux classes de base mais il a son avantages par rapport aux langues strictement typées.

4
répondu Chris Reid 2012-05-24 06:00:34

Je pense que certaines de ces réponses indiquent au moins l'idée que l'héritage est un moyen plus lourd d'ajouter des fonctionnalités à une classe existante, tandis que les catégories sont plus légères.

L'héritage est utilisé lorsque vous créez une nouvelle hiérarchie de classes (toutes les cloches et les sifflets) et apporte sans doute beaucoup de travail lorsqu'il est choisi comme méthode d'ajout de fonctionnalités aux classes existantes.

Comme quelqu'un d'autre ici l'a dit... Si vous utilisez l'héritage pour ajouter une nouvelle méthode par exemple à NSString, vous devez aller et changer le type que vous utilisez dans n'importe quel autre code où vous voulez utiliser cette nouvelle méthode. Si, cependant, vous utilisez des catégories, vous pouvez simplement appeler la méthode sur les types NSString existants, sans sous-classer.

Les mêmes fins peuvent être atteintes avec l'un ou l'autre, mais les catégories semblent nous donner une option plus simple et nécessitant moins de maintenance (probablement).

Quelqu'un sait s'il y a des situations où les catégories sont absolument nécessaires?

3
répondu user3881658 2016-04-06 04:50:54

Une catégorie est comme un mixin: un module en Ruby, ou un peu comme une interface en Java. Vous pouvez le considérer comme des "méthodes nues". Lorsque vous ajoutez une catégorie, vous ajoutez des méthodes à la classe. L'article Wikipedia a bonnes choses .

2
répondu Charlie Martin 2009-12-09 05:26:46

La meilleure façon de regarder cette différence est que: 1. héritage: quand voulez-vous le transformer exactement sur votre chemin. exemple: AsyncImageView pour implémenter le chargement paresseux. Ce qui est fait en héritant UIView. 2. catégorie : voulez Juste ajouter une saveur supplémentaire à elle. exemple: nous voulons remplacer tous les espaces du texte d'un champ de texte

   @interface UITextField(setText)
      - (NSString *)replaceEscape;
   @end

   @implementation UITextField(setText)
      - (NSString *)replaceEscape
      {
         self.text=[self.text stringByTrimmingCharactersInSet:
                           [NSCharacterSet whitespaceCharacterSet]];
         return self.text;
      }
   @end

- - - il ajoutera une nouvelle propriété à textfield pour que vous puissiez échapper à tous les espaces blancs. Tout comme l'ajout d'une nouvelle dimension, sans changer complètement son façon.

0
répondu Avik Roy 2012-07-06 02:31:54