Question

Quelqu'un peut me expliquer la différence entre les catégories et l'héritage en Objective C? J'ai lu l'entrée dans Wikipedia et la discussion sur les catégories il ne pas air différent à celui de l'héritage. J'ai aussi regardé la discussion sur le sujet dans le livre « Open iPhone Development » et je ne comprends toujours pas.

Était-ce utile?

La solution

Parfois, l'héritage semble comme plus d'ennuis que cela vaut la peine. Il est correctement utilisé lorsque vous voulez ajouter quelque chose à une classe existante qui est un changement dans le comportement de cette classe.

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

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

Les catégories sont un bon moyen d'ajouter des fonctionnalités tout en même temps conforme à un principe orienté objet à préférer la composition sur l'héritage.

Modifier Janvier 2012

Les choses ont changé maintenant. Avec le compilateur LLVM actuel, et le moderne, l'exécution 64 bits, vous pouvez ajouter Ivars et propriétés à la classe extensions (pas de catégories). Cela vous permet de garder Ivars privé de l'interface publique. Mais, si vous déclarez des propriétés pour les Ivars, ils peuvent encore être consultés / changé par KVC, parce qu'il n'y a toujours pas une telle chose comme une méthode privée en Objective-C.

Autres conseils

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

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

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

AppKit définit une catégorie de NSString qui fournit des méthodes de dessin supplémentaires. La catégorie permet de nouvelles méthodes à ajouter à une classe existante, donc nous sommes toujours juste face à NSStrings. Si AppKit au lieu de dessin mis en œuvre par subclassing que nous aurions à traiter « AppKitStrings » ou « NSSDrawableStrings » ou quelque chose comme ça.

Les catégories vous permettent d'ajouter des applications ou du domaine des méthodes spécifiques aux classes existantes. Il peut être assez puissant et pratique.

Si vous en tant que programmeur donne un ensemble complet de code source pour une bibliothèque ou à l'application du code, vous pouvez aller de noix et de changer tout ce que 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 vous êtes donné un kit de bibliothèque / objet binaire et un ensemble de têtes à faire avec.

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

  1. créer une nouvelle classe entière au lieu d'une classe d'actions -. Reproduisant toutes ses fonctions et membres réécrire alors tout le code pour utiliser la nouvelle classe

  2. créer une nouvelle classe d'emballage qui contient la classe d'actions en tant que membre (compositing) et réécrire le code de base pour utiliser la nouvelle classe.

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

  4. forcer le compilateur à voir votre nouvelle classe comme l'ancien et nous espérons qu'elle ne dépend pas d'une certaine taille ou dans les points de mémoire et d'entrée spécifiques.

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

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

    Cela peut aussi corriger les erreurs dans la bibliothèque ou de personnaliser les méthodes pour les nouveaux périphériques matériels ou peu importe. Il n'est pas une panacée, mais elle permet de méthode de classe ajoutant sans recompiler la classe / bibliothèque qui ne change pas. La classe d'origine est le même dans le code, la taille de la mémoire et des points d'entrée, de sorte que les applications existantes ne se cassent pas. Le compilateur met simplement la nouvelle méthode (s) dans le moteur d'exécution comme appartenant à cette catégorie, et remplace les méthodes avec la même signature que dans le code original.

    un exemple:

    Vous avez un Bing de classe qui délivre à un terminal, mais pas à un port série, et maintenant est ce que 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 ce que tout, vous avez juste le api public dans l'en-tête.

    Vous êtes intelligent, vous créez 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é avec votre application et l'exécution sait maintenant que Bing répond à @selector (ToSerial :) et vous pouvez l'utiliser comme si la classe Bing a été construit avec cette méthode. Vous ne pouvez pas ajouter cela n'a été méthodes membres de données et ne sont pas destinés à créer des tumeurs géantes de code attachées aux classes de base, mais il a ses avantages par rapport aux langues strictement typés.

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

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

Comme quelqu'un d'autre ici le mettre ... Si vous utilisez l'héritage d'ajouter une nouvelle méthode par exemple NSString, vous devez aller et changer le type que vous utilisez dans tout autre code où vous souhaitez utiliser cette nouvelle méthode. Toutefois, si vous utilisez des catégories, vous pouvez simplement appeler la méthode sur les types existants NSString, sans sous-classement.

peuvent être atteints Les mêmes extrémités soit, mais les catégories semblent nous donner une option qui est plus simple et nécessite moins d'entretien (probablement).

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

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

La meilleure façon de regarder est que, à cette différence: 1. héritage: quand vous le mettre exactement dans votre chemin. exemple: AsyncImageView pour mettre en œuvre le chargement paresseux. Ce qui est fait en héritant UIView. 2. Catégorie: Je veux 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 vous d'échapper à tous les espaces blancs. Tout comme l'ajout d'une nouvelle dimension à elle sans changer complètement son chemin.

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