Frage

Ich habe mehrere Jahre Erfahrung in der Obj-c und Kakao, aber ich bin gerade jetzt wieder in sie bekommen und die Fortschritte von Obj-C 2.0 etc.

Ich versuche, meinen Kopf um die moderne Laufzeit und erklären Eigenschaften zu bekommen, usw. Eine Sache, die mich ein bisschen verwirrt, ist die Fähigkeit, in der modernen Laufzeit die Ivars implizit erstellt zu haben. Und natürlich bedeutet dies, dass Sie in Ihrem Code sollte immer self.property werden über den Wert zuzugreifen.

Doch in init * und dealloc (vorausgesetzt, Sie verwenden GC nicht) Methoden sollten wir (in der aktuellen Laufzeit) die iVar direkt werden.

So Fragen sind:

  1. Sollten wir Eigenschaftenaccessoren in init * und dealloc mit modernen Runtime?

  2. Wenn ja , warum ist das anders? Ist es nur, weil der Compiler die iVar nicht?

  3. Wenn ich einen Accessor außer Kraft setzen müssen, kann ich immer noch, dass iVar zugreifen, die zur Laufzeit definiert werden, oder muss ich einen tatsächlichen iVar definieren, dass die Laufzeit wird dann benutzen?

  4. Auch hier , wenn ich das synthetisierte iVar zugreifen , warum kann ich nicht weiter dies für die init * und dealloc Methoden tun?

Ich habe gelesen, die mehrmals docs, aber sie schien dies alles ein wenig vage und ich sicher sein will, dass ich es gut, um zu entscheiden, zu verstehen, wie ich fortsetzen will Codierung.

Ich hoffe, dass meine Fragen klar sind.


Kurze Zusammenfassung der Prüfung :

  1. Wenn Sie die Ivar in Vermächtnis nicht erklären, Compiler ist vollständig unglücklich

  2. Wenn Sie #ifndef __OBJC2__ um Ivar in Legacy verwenden Compiler ist glücklich, und Sie können sowohl Ivar direkt und als Eigenschaft

  3. In der modernen Laufzeit können Sie die Ivar undefiniert und Zugang als Eigentum verlassen

  4. In der modernen Laufzeit, Ivar direkt ohne Anmeldung zuzugreifen versuchen, gibt Fehler während der Kompilierung

  5. @private Erklärung Ivar, natürlich, ermöglicht den direkten Zugriff auf Ivar in beide Erbe und moderne

gibt nicht wirklich eine saubere Art und Weise jetzt vorwärts zu gehen oder?

War es hilfreich?

Lösung

In der aktuellen (OS X 10.5 / GCC 4.0.1) Compiler, können Sie nicht direkt Zugriff auf die Runtime-synthetisierte ivars. Greg Parker, einer der OS X Runtime-Ingenieure es ausdrückte diese Weise auf der Kakao-dev Liste (12. März 2009):

  

Sie können nicht in den aktuellen Compiler. EIN   Zukunft Compiler sollte das in Ordnung bringen. Verwenden   explizite @private ivars in der   inzwischen. Ein @private Ivar sollte nicht   Bestandteil des Vertrages in Betracht gezogen werden -   das ist, was @private bedeutet, erzwungen   von Compiler-Warnungen und Linker   Fehler.

     

Und warum ist nicht es eine Möglichkeit,   erklären ausdrücklich Instanzvariablen   in der .m-Datei für die neue Laufzeit?

     

Drei Gründe: (1) gibt es einige   nicht-triviale Design-Details zu Arbeit   out, (2) Compiler-Ingenieur-Stunden sind   begrenzt ist, und (3) sind @private ivars   im Allgemeinen gut genug.

So, jetzt müssen Sie Punktnotation verwenden, um Eigenschaften zugreifen, auch in init und dealloc. Das geht gegen die beste Praxis der ivars direkt in diesen Fällen verwenden, aber es gibt keinen Weg drum herum. Ich finde, dass die Leichtigkeit der Runtime-synthetisierten ivars mit (und die Leistungsvorteile) überwiegt diese in den meisten Fällen. Wo Sie müssen die Ivar direkt zugreifen zu können, können Sie eine @private Ivar verwenden, wie Greg Parker schlägt vor (es gibt nichts, das explizit deklariert und Runtime-synthetisierte ivars verhindert, dass Sie Mischen).

Aktualisieren Mit OS X 10.6, die 64-Bit-Laufzeit einen direkten Zugang zu den synthetisierten ivars über self->ivar erlaubt.

Andere Tipps

Da Instanzvariablen selbst kann nur in der modernen Laufzeit synthetisiert werden (und muß in der @interface unter 32-Bit-oder Pre-Leopard deklariert werden), ist es am sichersten / portabelste auch die Ivar zu erklären

  
      
  • Sollten wir Eigenschaftenaccessoren in init * und dealloc mit modernen Runtime?
  •   

Meine Faustregel „möglicherweise“ für -init*, und „in der Regel nicht“ für -dealloc.

Wenn Sie ein Objekt zu initialisieren, Sie wollen richtig sicherstellen zu kopieren / behalten Werte für ivars. Es sei denn, der Setter Eigentum einige Nebeneffekt hat, dass sie ungeeignet für die Initialisierung macht, auf jeden Fall die Abstraktion wieder verwenden die Eigenschaft bereitstellt.

Wenn Sie ein Objekt ausplanen wollen Sie Ivar Objekte freizugeben, aber nicht neue zu speichern. Eine einfache Möglichkeit, dies zu tun, ist die Eigenschaft auf null (myObject.myIvar = nil) zu setzen, die im Grunde [myObject setMyIvar:nil] nennt. Da Nachrichten auf Null ignoriert werden, besteht keine Gefahr, in diesem. Es ist jedoch übertrieben, wenn [myIvar release]; in der Regel alles, was Sie brauchen. In der Regel verwenden Sie nicht die Eigenschaft (oder direkt, die Setter) sollten in Situationen, in denen Deallokation verhalten sich anders als die variable Einstellung.

Ich kann eJames' Argument gegen die Verwendung von Eigenschaftenaccessoren in init / dealloc überhaupt, aber die Kehrseite ist, dass wenn Sie die Eigenschaft Verhalten zu ändern (zum Beispiel aus der Veränderung zu kopieren behalten, oder einfach nur zuweisen, ohne Halt) und don‘verstehen t es in init verwenden, oder umgekehrt, kann das Verhalten auch nicht mehr synchronisiert ist. Wenn die Initialisierung und eine Ivar Modifizierung sollte die gleiche handeln, die Eigenschaftenaccessor für beide verwenden.

  
      
  • Wenn ja, warum ist das anders? Ist es nur, weil der Compiler die Ivar nicht sehen kann?
  •   

Die modernen Laufzeit befasst sich mit der Klassengröße und das Layout intelligenter, weshalb Sie das Layout ivars ändern können, ohne Unterklassen neu kompilieren zu müssen. Es ist auch in der Lage, den Namen und den Typ des Ivar Sie aus dem Namen und den Typ der entsprechenden Eigenschaft abzuleiten. Die Objective-C 2.0 Runtime Programming Guide weitere Informationen hat, aber wieder, ich weiß nicht, wie tief die Details dort erläutert.

  
      
  • Wenn ich einen Accessor außer Kraft setzen müssen, kann ich immer noch, dass iVar zugreifen, die zur Laufzeit definiert werden, oder muss ich eine tatsächliche iVar zu definieren, dass die Laufzeit wird dann benutzen?
  •   

ich nicht getestet haben, aber ich glaube, Sie erlaubt den Namen Ivar in Code zugreifen zu können, da es tatsächlich erstellt werden muss. Ich bin nicht sicher, ob der Compiler wird sich beschweren, aber ich würde vermuten, dass da es Ihnen die Ivar synthetisieren lassen, ohne klagen, ist es auch klug genug ist, um die synthetisierte Ivar kennen und lassen Sie sie mit Namen beziehen.

  
      
  • Auch wenn ich das synthetisierte iVar zugreifen kann, warum kann ich nicht weiter dies für die init * und dealloc Methoden tun?
  •   

Sie sollten das Eigentum und / oder ivar jederzeit zugreifen können, nachdem die Instanz zugeordnet ist.

Es gibt eine andere SO mit ähnlichen Informationen Frage , aber es ist nicht ganz ein Duplikat.

In der unteren Zeile, von den Objective-C 2.0-Dokumentation und von Mark Bessey Antwort ist wie folgt:

  

Es gibt Unterschiede im Verhalten, die auf der Laufzeit abhängig (siehe auch „Runtime Differences“):

     

Für das Legacy-Runtimes, Instanzvariablen müssen bereits im @interface Block deklariert werden. Wenn eine Instanzvariable mit dem gleichen Namen und kompatibelem Typ wie die Eigenschaft vorhanden, er wird verwendet, sonst wird man einen Compiler-Fehler erhalten.

     

Für die moderne Runtimes, Instanzvariablen werden je nach Bedarf synthetisiert. Wenn eine Instanzvariable mit dem gleichen Namen bereits vorhanden ist, es verwendet wird.

Mein Verständnis ist, wie folgt:

Sie sollten nicht Eigenschaftenaccessoren in init* und dealloc Methoden, aus den gleichen Gründen, die Sie nicht, sie in der alten Laufzeit verwendet werden sollen: Es läßt Dich offen für mögliche Fehler, wenn Sie später die Eigenschaft Methoden außer Kraft setzen, und am Ende etwas zu tun das sollte nicht in init* oder dealloc erfolgen.

Es soll möglich sein, um sowohl die Ivar synthetisieren und die Eigenschaft Methoden außer Kraft setzen, wie folgt:

@interface SomeClass
{
}
@property (assign) int someProperty;
@end

@implementation SomeClass
@synthesize someProperty; // this will synthesize the ivar
- (int)someProperty { NSLog(@"getter"); return someProperty; }
- (void)setSomeProperty:(int)newValue
{
    NSLog(@"setter");
    someProperty = newValue;
}
@end

Das führt mich zu glauben, dass Sie auch den synthetisierte Ivar in Ihren init* und dealloc Methoden zugreifen zu können. Die einzige Gotcha ich denken konnte, ist, dass die @synthesize Linie kommen müssen möglicherweise vor die Definitionen Ihrer init* und dealloc Methoden in der Quelldatei.

Am Ende, da die ivars in der Schnittstelle funktioniert noch erklärt hat, das ist immer noch die sicherste Wette.

ich in das gleiche Problem leite. Die Art und Weise arbeite ich um nicht die synthetisierten Instanzvariablen zugreifen zu können ist die folgende:

public-Header

@interface MyObject:NSObject {
}
@property (retain) id instanceVar;
@property (retain) id customizedVar;
@end

Private Header / Implementierung

@interface MyObject()
@property (retain) id storedCustomizedVar;
@end

@implementation MyObject
@synthesize instanceVar, storedCustomizedVar;
@dynamic customizedVar;

- customizedVar {
  if(!self.storedCustomizedVar) {
    id newCustomizedVar;
    //... do something
    self.storedCustomizedVar= newCustomizedVar;
  }
  return self.storedCustomizedVar;
}

- (void) setCustomizedVar:aVar {
  self.storedCustomizedVar=aVar;
}

@end

Es ist nicht so elegant, aber zumindest hält meine öffentliche Header-Datei sauber.

Wenn Sie KVO benötigen Sie customizedVar als abhängiger Schlüssel von storedCustomizedVar zu definieren.

Ich bin relativ neu in Obj-C (aber nicht in der Programmierung) und werde auch von diesem Thema verwechselt worden.

Der Aspekt, der mir Sorgen macht, ist, dass es relativ einfach zu sein scheint, die iVar anstelle der Eigenschaft versehentlich zu verwenden. Zum Beispiel schreiben:

MyProp = someobject;

statt

self.myProp = someobject;

Zwar ist dieses „user“ Fehler, aber es scheint immer noch recht einfach aus Versehen in einigem Code zu tun, und für eine zurückgehalten oder Atom Eigenschaft könnte es vermutlich zu Problemen führen.

Im Idealfall würde ich in der Lage sein es vorziehen, die Laufzeit zu bekommen einige Muster auf den Eigenschaftsnamen anzuwenden bei der Generierung von alle iVar. Z.B. Präfix sie immer mit "_".

In der Praxis im Moment habe ich dies manuell tue - mein ivars ausdrücklich erklärt, und sie absichtlich verschiedene Namen von den Eigenschaften. Ich benutze einen alten Stil ‚m‘ Präfix, also wenn mein Eigentum „MyProp“, wird mein iVar sein „mMyProp“. Dann benutze ich @synthesize MyProp = mMyProp die beiden zu verbinden.

Das ist ein bisschen ungeschickt Ich gebe zu, und ein bisschen mehr schreiben, aber es scheint, lohnt sich für mich in der Lage zu sein, ein wenig deutlicher im Code eindeutig zu machen. Natürlich kann ich es immer noch falsch und mMyProp = someobject, aber ich hoffe, dass das ‚m‘ prefix mich auf meine Fehler aufmerksam eingeben.

Es wäre viel schöner fühlen, wenn ich nur die Eigenschaft erklären könnte und lassen Sie den Compiler / runtime den Rest, aber wenn ich eine Menge Code mein Bauchgefühl haben sagt mir, dass ich Fehler, die Art und Weise machen werde, wenn ich immer noch folgen manuelle Regeln für init / dealloc.

Natürlich gibt es auch viele andere Dinge, die ich kann auch falsch gemacht ...

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