Frage

Kann jemand mir den Unterschied zwischen den Kategorien und Vererbung in Objective C erklären? Ich habe den Eintrag in Wikipedia und die Diskussion über die Kategorien tut es nicht schaut anders zu, dass die Vererbung. Ich sah auch an der Diskussion über das Thema in dem Buch „Open iPhone Development“ und ich es immer noch nicht.

War es hilfreich?

Lösung

Manchmal, Vererbung scheint wie mehr Mühe, als es wert ist. Es ist richtig eingesetzt, wenn Sie etwas zu einer vorhandenen Klasse hinzufügen möchten, die eine Änderung des Verhaltens dieser Klasse ist.

Mit einer Kategorie, wollen Sie nur das vorhandene Objekt ein wenig mehr zu tun. Wie bereits gegeben, wenn Sie nur eine String-Klasse haben wollen, dass die Kompression behandelt, brauchen Sie nicht die String-Klasse, Unterklasse, die Sie gerade eine Kategorie erstellen, die die Kompression behandelt. Auf diese Weise brauchen Sie nicht den Typ der Zeichenfolge Klassen zu ändern, die Sie bereits verwenden.

Der Schlüssel ist in der Einschränkung, dass Kategorien nur Methoden hinzufügen, können Sie keine Variablen zu einer Klasse hinzufügen Kategorien verwenden. Wenn die Klasse mehr Eigenschaften braucht, dann hat es subclassed werden.. (Edit: Sie assoziative Speicher verwenden kann, glaube ich)

Kategorien sind eine nette Art und Weise Funktionalität hinzufügen, während zur gleichen Zeit zu einem objektorientierten Prinzip konforme Komposition der Vererbung bevorzugen.

Bearbeiten Januar 2012

Die Dinge haben sich jetzt geändert. Mit dem aktuell LLVM Compiler und der modernen, 64-Bit-Laufzeit können Sie Ivars und Eigenschaften der Klasse Erweiterungen (nicht Kategorien) hinzufügen. Auf diese Weise können Sie private Ivars aus der öffentlichen Schnittstelle halten. Aber, wenn Sie Eigenschaften für die Ivars erklären, können sie immer noch über KVC zugegriffen / geändert werden, weil es noch nicht so etwas wie eine private Methode in Objective-C ist.

Andere Tipps

Kategorien können Sie Methoden, um bestehende Klassen hinzuzufügen. Also anstatt Unterklasse NSData Ihre flippigen neuen Verschlüsselungsmethoden hinzufügen, können Sie sie direkt an die NSData Klasse hinzuzufügen. Jedes NSData Objekt in Ihrer Anwendung hat nun Zugriff auf diese Methoden.

Um zu sehen, wie nützlich das sein kann, schauen Sie unter: CocoaDev

Eines der beliebtesten Illustrationen von Objective-c Kategorien in Aktion ist NSString. NSString ist in der Stiftung Rahmen definiert, die keine Ahnung von Ansichten oder Fenstern haben. Wenn Sie jedoch eine NSString in einer Cocoa-Anwendung verwenden, werden Sie bemerken, dass es auf Nachrichten wie – drawInRect:withAttributes: reagiert.

AppKit definiert eine Kategorie für NSString, die zusätzliche Ziehverfahren zur Verfügung stellt. Die Kategorie ermöglicht es, neue Methoden zu einer vorhandenen Klasse hinzugefügt werden, so dass wir nach wie vor nur mit NSStrings zu tun. Wenn AppKit anstelle von Subklassen implementiert zeichnen wir würden mit ‚AppKitStrings‘ oder ‚NSSDrawableStrings‘ oder so etwas zu tun haben.

Kategorien können Sie Anwendung oder domänenspezifische Methoden, um bestehende Klassen hinzuzufügen. Es kann sehr mächtig und bequem sein.

Wenn Sie als Programmierer einen vollständigen Satz von Quellcode für eine Code-Bibliothek oder Anwendung gegeben sind, können Sie Nüsse gehen und ändern, was Sie benötigen, um Ihre Programmierung Ziel mit diesem Code zu erreichen.

Leider ist dies nicht immer der Fall oder sogar wünschenswert. Viele Male Sie eine binäre Bibliothek / Objekt-Kit und eine Reihe von Header mit machen gegeben sind zu tun.

Dann wird eine neue Funktionalität ist für eine Klasse benötigt, so dass Sie ein paar Dinge tun können:

  1. Erstellen Sie eine neue Klasse ganze anstelle einer Aktienklasse -. Replizieren alle seine Funktionen und die Mitglieder dann den gesamten Code umschreiben die neue Klasse zu verwenden,

  2. Erstellen Sie eine neue Wrapper-Klasse, die die Aktienklasse als Mitglied (Compositing) enthält und schreiben Sie den Code-Basis die neue Klasse zu nutzen.

  3. binäre Patches der Bibliothek des Codes (viel Glück) zu ändern

  4. den Compiler zwingen, die neue Klasse wie das alte zu sehen und zu hoffen, dass es nicht auf eine bestimmte Größe oder Platz im Speicher und spezifische Einstiegspunkte abhängt.

  5. Unterklasse Spezialisierung - Subklassen erstellen Funktionen hinzuzufügen und Treibercode zu ändern, anstatt die Unterklasse nutzen - theoretisch sollte es einige Probleme, und wenn Sie Datenelemente hinzufügen müssen es notwendig ist, aber der Speicherbedarf wird anders. Sie haben den Vorteil, dass sowohl den neuen Code und den alten Code in der Unterklasse und die Entscheidung, welche die Basisklassenmethode oder die überschriebene Methode verwenden.

  6. die notwendige objc-Klasse mit einer Kategoriedefinition ändern Methoden enthalten, zu tun, was Sie wollen, und / oder die alten Methoden in den Aktienklassen außer Kraft setzen.

    Dies kann auch Fehler in der Bibliothek beheben oder Methoden für neue Hardware-Geräte oder was auch immer anpassen. Es ist kein Allheilmittel, aber es ermöglicht Klassenmethode zu ändern, ohne die Klasse / Bibliothek neu zu kompilieren, die unverändert ist. Die ursprüngliche Klasse ist das gleiche in Code, Speichergröße und Eintrittspunkten, so Legacy-Anwendungen nicht brechen. Der Compiler setzt einfach die neue Methode (n) in die Laufzeit als Zugehörigkeit zu dieser Klasse, und überschreibt Methoden mit derselben Signatur wie in dem ursprünglichen Code.

    ein Beispiel:

    Sie haben eine Klasse Bing, die an einen Terminal ausgibt, aber nicht an einen seriellen Anschluss, und jetzt das ist, was Sie brauchen. (aus irgendeinem Grund). Sie haben Bing.h und libBing.so, aber nicht Bing.m in Ihrem Kit.

    Die Bing Klasse nicht alle möglichen Dinge intern, wissen Sie nicht einmal alle, was Sie gerade die öffentliche api im Header haben.

    Sie sind smart, so dass Sie eine (SerialOutput) Kategorie für die Bing-Klasse erstellen.

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

    Der Compiler verpflichtet, ein Objekt zu erstellen, die jetzt mit der App verknüpfen in und die Laufzeit werden können, weiß, dass Bing nach @selector reagiert (ToSerial :) und Sie können es als verwenden, wenn die Bing-Klasse mit dieser Methode gebaut wurde. Sie können keine Daten nur für Mitglieder Methoden hinzufügen und diese wurden nicht an Basisklassen sollen angebracht riesige Tumoren von Code erstellen, aber es hat seine Vorteile über streng typisierten Sprachen.

Ich denke, einige dieser Antworten zumindest Punkt auf der Idee, dass Vererbung ist ein schwerer Weg Funktionalität zu einer vorhandenen Klasse hinzuzufügen, während Kategorien leichter sind.

Vererbung verwendet, wenn Sie eine neue Klassenhierarchie sind zu schaffen (alle Glocken und Trillerpfeifen) und wohl auch eine Menge Arbeit bringt, wenn als das Verfahren zum Hinzufügen von Funktionen zu bestehenden Klassen ausgewählt.

Wie jemand anderes es hier setzen ... Wenn Sie Vererbung verwenden, ein neues Verfahren zum Beispiel zu NSString hinzufügen möchten, müssen Sie die Art gehen und ändern Sie in jedem anderen Code verwenden, wo Sie diese neue verwenden wollen Methode. Wenn Sie jedoch Kategorien verwenden, können Sie einfach die Methode aufrufen, auf bestehende NSString Typen, ohne Subclassing.

Die gleichen Enden können mit entweder erreicht werden, aber Kategorien scheinen uns die Möglichkeit zu geben, die einfacher und erfordert weniger Wartung (wahrscheinlich).

Wer weiß, ob es gibt Situationen, in denen Kategorien sind absolut notwendig?

Eine Kategorie ist wie ein mixin: ein Modul in Ruby oder etwas wie eine Schnittstelle in Java. Sie können als „nackte Methoden“ daran denken. Wenn Sie eine Kategorie hinzufügen, sind das Hinzufügen Sie Methoden der Klasse. Der Wikipedia-Artikel hat good stuff .

Der beste Weg, um diesen Unterschied zu sehen ist, dass: 1. Vererbung: wenn es genau in den Weg machen wollen. Beispiel: AsyncImageView verzögertes Laden zu implementieren. Welche wird durch Erben UIView getan. 2. Kategorie: Ich will nur einen extraen Geschmack, um es hinzuzufügen. Beispiel: Wir wollen alle Räume von einem Textfeld des Text ersetzen

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

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

--- Es wird eine neue Eigenschaft in der textfield für Sie alle weißen Flächen zu entkommen. Genau wie eine neue Dimension, um es zu ändern, ohne seinen Weg vollständig zu verändern.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top