2009-06-17 21 views
2

Ich arbeite Objective-C auf dem Lernen, und ich versuche, ein Gefühl für die Speicherverwaltung zu erhalten. Ich bin ziemlich vertraut mit C-Speicherverwaltung, aber ich versuche herauszufinden, wie anders ObjC ist.Objective C-Speicherverwaltung für anonyme Objekte

Lassen Sie uns sagen, dass ich eine Klasse Complex genannt, die zur Aufnahme von komplexen Zahlen verwendet, die ein Verfahren -(Complex*)add:(Complex*)c; hat, dass die in komplexe Zahl zu self weitergegeben fügt (Complex ist ein veränderliches Objekt, sagen wir mal).

So kann ich es nenne diese Art und Weise:

Complex *c = [[Complex alloc] withReal: -3.0 andImag: -2.4]; // c = -3.0-2.4i 
[c add : [[Complex alloc] withReal: 1.0 andImag: 2.0]]; // now c = -2.0-0.4i 

Was für das temporäre Objekt in dem Speicher geschieht in dem Aufruf von add erstellt verwendet? Ich nehme an, es ist ein Speicherleck; Ist das der richtige Code?

Complex *c = [[Complex alloc] withReal: -3.0 andImag: -2.4]; // c = -3.0-2.4i 
Complex *b = [[Complex alloc] withReal: 1.0 andImag: 2.0]; // b = 1+2i 
[c add : b]; // now c = -2.0-0.4i 
[b release]; 

Bonus noob Frage: würde die Objective-C 2.0 GC mit der Situation umgehen?

Antwort

2

Zuerst, mit meiner "Best Practices" Hut auf, wenn Sie benutzerdefinierte Klassen erstellen, ist das Objective-C-Idiom die Initialisierer (gleichbedeutend mit "Konstruktoren" in anderen Sprachen) mit einem führenden "init". Versuchen Sie auch, Teile des Methodenselektors oder die benannten Parameter nicht zu verkürzen.

Zum Beispiel statt dessen:

- (id) withReal:(double)r andImag:(double)i { ... } 

sollten Sie dies in Erwägung ziehen:

- (id) initWithReal:(double)real imaginary:(double)imaginary { ... } 

Die „und“ vor dem zweiten Teil Geschmackssache ist - es ist durchaus akzeptabel zu verwenden es, aber ich bevorzuge es ohne, da Sie es wahrscheinlich nicht für Methoden mit 3+ Parametern verwenden würden. Zum Beispiel wäre es ausführlicher als notwendig, wenn Sie eine RGB-Farbe erstellen würden, um -initWithRed:andGreen:andBlue: zu verwenden - Schreiben/Verwenden von -initWithRed:green:blue: ist normalerweise vorzuziehen.


Für Ihre eigentliche Frage, ich bin völlig einverstanden, dass eine Komfort-Klasse Konstruktor Schaffung der intelligente Art und Weise für Situationen wie diese zu gehen. Es ist visuell viel sauberer als Alloc-Init-Autorelease jedes Mal, wenn Sie eine Wegwerf-Instanz benötigen. Passend zu den oben genannten Änderungen, würde ich zwicken @ Antwort des kent sehen wie folgt aus:

+ (Complex*) complexWithReal:(double)real imaginary:(double)imaginary { 
    return [[Complex alloc] initWithReal:real imaginary: imaginary] autorelease]; 
} 

Für die Bonus-Frage, ja, Objective-C 2.0 GC dies ganz gut behandeln würde; Der am besten geschriebene Retain-Release-Code funktioniert wie unter GC, besonders wenn Sie darauf achten, Zeiger auf Null zu setzen, wenn Sie sie nicht mehr benötigen. Wenn GC aktiviert ist, sind Aufrufe zum Beibehalten/Freigeben/Autorelease im Wesentlichen No-Ops und Objekte werden gesammelt, sobald keine Verweise darauf vorhanden sind. Sobald der letzte Zeiger auf ein Objekt verloren gegangen ist oder den lokalen Bereich verlässt, ist das Objekt für die Erfassung geeignet. (Technisch gesehen zählt der GC nur starke Referenzen, aber wenn Sie nicht wissentlich schwache Referenzen verwenden, ist die Unterscheidung wahrscheinlich im Moment irrelevant.) Denken Sie daran, dass Garbage Collection derzeit NICHT auf dem iPhone unterstützt wird.

+0

Danke für die GC-Tipps - aber es wird eine Weile dauern, bis ich den Kratzer habe, um mit einem iPhone zu spielen;) – decitrig

+0

Sicher Sache. GC ist großartig, wenn Sie es verwenden können, obwohl es bedeutet, dass Sie die Tiger-Unterstützung löschen müssen und alle verwendeten Frameworks auch GC unterstützen müssen. Aber mit der Zeit wird das immer alltäglicher werden und wer weiß, vielleicht werden die iPhones, wenn iPhones schneller werden, auch GC unterstützen. :-) –

2

Im ersten Beispiel:

[c add : [[Complex alloc] withReal: 1.0 andImag: 2.0]]; 

Sie Objekt mit Referenzzähler zugewiesen haben 1 und es freigegeben wird nicht so es Speicherleck ist, weil Sie auf dieses Objekt den Zeiger nicht speichern, so dass Sie nicht Sende die Freigabe an sie.

Sie ändern könnte es die ‚vorübergehend‘ Objekt zu Autorelease:

[c add : [[[Complex alloc] withReal: 1.0 andImag: 2.0] autorelease]]; 

Sie wahrscheinlich init im Namen der Tatsache hinweisen, verwenden würde, dass das Objekt nicht Autoreleased ist und der Benutzer den Speicher zu handhaben Management:

initWithReal:(double)r andImag:(double)i 

Das zweite Beispiel ist korrekt.

Cocoa bietet viele Methoden (sowohl statische als auch Mitglied), die Autoreleased Objekte beispielsweise zurückgeben [NSString stringWithString:@"example"] so könnten Sie Methoden erstellen, die Autoreleased Objekte zurück, so dass Sie mit Loslassen zu tun haben nicht:

Complex * c = [Complex complexWithReal:1.0 andImag:2.0] 

Sie könnten Erstellen Sie auch eine Methode, die Rohdaten z etwas wie addReal:(double)r andImag:(double)i, so dass Sie den Alloc/Init-Schritt überspringen können.

Eine weitere Option ist es, Strukturen zu verwenden, wie in Cocoa verwendet (CGRect und so weiter). Sie sind dieselben wie in C, was bedeutet, dass sie auf dem Stack zugeordnet sind und verschwinden, sobald sie den Gültigkeitsbereich verlassen, im Gegensatz zu allokierten Objekten auf dem Heap mit alloc/init. Gut für "kleine" Objekte, die häufig verwendet werden, aber oft nicht möchten.

Bezüglich GC sehe ich keinen Grund, warum GC nicht in der Lage sein würde, das Objekt freizugeben - ich habe es jedoch nicht oft benutzt (nur ein paar Beispiele geschaut - ich bevorzuge es, den Speicher selbst zu verwalten - es sei denn mit python ...)

1

StefanB ist richtig. da Sie es eine Menge dieses ‚on the fly‘ Instanziierung (ich würde davon ausgehen, ...) sinnvoll, eine statische ‚Bequemlichkeit‘ Konstruktor bauen würde tun werden (es gibt jede Menge Beispiele für diese in den AppKit & co.)

+(Complex*) complexWithReal:(double)r andImag:(double)i 
{ 
    return [[Complex alloc] initWithReal:r andImag:i] autorelease]; 
} 

, die Ihren Anruf Nachricht hinzufügen würde dann wie folgt aussehen:

[c add : [Complex complexWithReal:2.0 andImage:1.0]] 

Spaß haben!