Beginnen wir mit retain
und release
; autorelease
ist wirklich nur ein Sonderfall, wenn Sie die Grundkonzepte verstanden haben.
In Cocoa verfolgt jedes Objekt, wie oft auf es verwiesen wird (insbesondere NSObject
implementiert die Basisklasse dies). Wenn Sie retain
ein Objekt aufrufen , teilen Sie ihm mit, dass Sie seine Referenzanzahl um eins erhöhen möchten. Durch Aufrufen release
teilen Sie dem Objekt mit, dass Sie es loslassen, und sein Referenzzähler wird dekrementiert. Wenn nach dem Aufruf release
der Referenzzähler jetzt Null ist, wird der Speicher dieses Objekts vom System freigegeben.
Der einfachste Weg , dies unterscheidet sich von malloc
und free
ist , dass eine bestimmte Aufgabe nicht über andere Teile des Systems zu sorgen braucht abstürzt , weil Sie Speicher freigegeben haben sie verwendet haben . Angenommen, jeder spielt mit und behält / gibt gemäß den Regeln frei. Wenn ein Code das Objekt behält und dann freigibt, bleibt jeder andere Code, der ebenfalls auf das Objekt verweist, unberührt.
Was manchmal verwirrend sein kann, ist zu wissen, unter welchen Umständen Sie anrufen sollten retain
und release
. Meine allgemeine Faustregel lautet: Wenn ich längere Zeit an einem Objekt festhalten möchte (z. B. wenn es sich um eine Mitgliedsvariable in einer Klasse handelt), muss ich sicherstellen, dass die Referenzanzahl des Objekts über mich Bescheid weiß. Wie oben beschrieben, wird der Referenzzähler eines Objekts durch Aufrufen erhöht retain
. Konventionell wird es auch erhöht (wirklich auf 1 gesetzt), wenn das Objekt mit einer "init" -Methode erstellt wird. In beiden Fällen liegt es in meiner Verantwortung, release
das Objekt aufzurufen, wenn ich damit fertig bin. Wenn ich das nicht tue, wird es einen Speicherverlust geben.
Beispiel für die Objekterstellung:
NSString* s = [[NSString alloc] init]; // Ref count is 1
[s retain]; // Ref count is 2 - silly
// to do this after init
[s release]; // Ref count is back to 1
[s release]; // Ref count is 0, object is freed
Nun zu autorelease
. Die Autorelease wird als bequeme (und manchmal notwendige) Methode verwendet, um das System anzuweisen, dieses Objekt nach einer Weile freizugeben. Aus Sanitärsicht autorelease
wird der aktuelle Thread NSAutoreleasePool
beim Aufruf über den Anruf informiert. Das NSAutoreleasePool
weiß jetzt, dass es release
das Objekt aufrufen kann, sobald es eine Gelegenheit erhält (nach der aktuellen Iteration der Ereignisschleife) . Aus unserer Sicht als Programmierer kümmert es sich darum, release
uns anzurufen, also müssen wir nicht (und sollten es auch nicht).
Was Anmerkung Wichtig ist , dass (wieder durch Konvention) alle Objekterstellung Klasse Methoden geben ein Autoreleased Objekt. Im folgenden Beispiel hat die Variable "s" beispielsweise einen Referenzzähler von 1, der jedoch nach Abschluss der Ereignisschleife zerstört wird.
NSString* s = [NSString stringWithString:@"Hello World"];
Wenn Sie an dieser Zeichenfolge festhalten möchten, müssen Sie sie retain
explizit aufrufen und dann explizit release
, wenn Sie fertig sind.
Betrachten Sie den folgenden (sehr erfundenen) Code, und Sie werden eine Situation sehen, in der dies autorelease
erforderlich ist:
- (NSString*)createHelloWorldString
{
NSString* s = [[NSString alloc] initWithString:@"Hello World"];
// Now what? We want to return s, but we've upped its reference count.
// The caller shouldn't be responsible for releasing it, since we're the
// ones that created it. If we call release, however, the reference
// count will hit zero and bad memory will be returned to the caller.
// The answer is to call autorelease before returning the string. By
// explicitly calling autorelease, we pass the responsibility for
// releasing the string on to the thread's NSAutoreleasePool, which will
// happen at some later time. The consequence is that the returned string
// will still be valid for the caller of this function.
return [s autorelease];
}
Mir ist klar, dass dies alles etwas verwirrend ist - irgendwann wird es jedoch klicken. Hier sind einige Referenzen, die Sie zum Laufen bringen:
- Apples Einführung in die Speicherverwaltung.
- Cocoa Programming für Mac OS X (4. Ausgabe) von Aaron Hillegas - ein sehr gut geschriebenes Buch mit vielen großartigen Beispielen. Es liest sich wie ein Tutorial.
- Wenn Sie wirklich eintauchen, können Sie zur Big Nerd Ranch gehen . Dies ist eine Schulungseinrichtung, die von Aaron Hillegas - dem Autor des oben genannten Buches - betrieben wird. Ich habe dort vor einigen Jahren den Intro to Cocoa-Kurs besucht und es war eine großartige Möglichkeit zu lernen.
NSString* s = [[NSString alloc] initWithString:@"Hello World"];
ein automatisch freigegebenes Objekt zurückgegeben wird (während Sie es schreiben), warum muss ich dann einreturn [s autorelease];
"autorelease" erneut einstellen und nicht nurreturn s
?[[NSString alloc] initWithString:@"Hello World"]
KEIN automatisch freigegebenes Objekt zurück. Bei jedemalloc
Aufruf wird der Referenzzähler auf 1 gesetzt, und es liegt in der Verantwortung dieses Codes, sicherzustellen, dass er freigegeben wird. Der[NSString stringWithString:]
Aufruf, auf der anderen Seite, nicht zurückkehrt ein Autoreleased Objekt.Wenn Sie den Prozess der Aufbewahrung / Freigabe verstehen, gibt es zwei goldene Regeln, die für etablierte Cocoa-Programmierer "duh" offensichtlich sind, aber für Neulinge leider selten klar formuliert werden.
Wenn eine Funktion, die ein Objekt zurückgibt
alloc
,create
odercopy
in ihrem Namen vorhanden ist, gehört das Objekt Ihnen. Sie müssen anrufen,[object release]
wenn Sie damit fertig sind. OderCFRelease(object)
wenn es sich um ein Core-Foundation-Objekt handelt.Wenn der Name keines dieser Wörter enthält, gehört das Objekt einer anderen Person. Sie müssen aufrufen,
[object retain]
wenn Sie das Objekt nach dem Ende Ihrer Funktion behalten möchten.Es wäre gut, wenn Sie diese Konvention auch in Funktionen befolgen würden, die Sie selbst erstellen.
(Nitpickers: Ja, es gibt leider einige API-Aufrufe, die Ausnahmen von diesen Regeln darstellen, aber selten sind.)
quelle
Wenn Sie Code für den Desktop schreiben und auf Mac OS X 10.5 abzielen können, sollten Sie zumindest die Verwendung der Objective-C-Garbage Collection in Betracht ziehen. Dies wird den größten Teil Ihrer Entwicklung wirklich vereinfachen. Deshalb hat Apple alle Anstrengungen unternommen, um es überhaupt erst zu erstellen und eine gute Leistung zu erzielen.
Wie für die Speicherverwaltungsregeln, wenn GC nicht verwendet wird:
+alloc/+allocWithZone:
,+new
,-copy
oder ,-mutableCopy
oder wenn Sie-retain
ein Objekt, nehmen Sie den Besitz davon und muss dafür sorgen , es gesendet wird-release
.-release
.-release
, können Sie es entweder selbst senden oder Sie können das Objekt senden,-autorelease
und der aktuelle Autorelease-Pool sendet es-release
(einmal pro Empfang-autorelease
), wenn der Pool geleert wird.Typischerweise
-autorelease
wird als eine Möglichkeit , um sicherzustellen , dass Objekte verwendet für die Länge des aktuellen Ereignisses leben, sind aber danach gereinigt, da es ein Autofreigabepool ist die Cocoa Ereignisverarbeitung umgibt. In Cocoa ist es weitaus üblicher, Objekte an einen Aufrufer zurückzugeben, die automatisch freigegeben wurden, als Objekte zurückzugeben, die der Aufrufer selbst freigeben muss.quelle
Objective-C verwendet die Referenzzählung, dh jedes Objekt hat eine Referenzzählung. Wenn ein Objekt erstellt wird, hat es einen Referenzzähler von "1". Einfach ausgedrückt, wenn auf ein Objekt verwiesen wird (dh irgendwo gespeichert wird), wird es "beibehalten", was bedeutet, dass seine Referenzanzahl um eins erhöht wird. Wenn ein Objekt nicht mehr benötigt wird, wird es "freigegeben", was bedeutet, dass seine Referenzanzahl um eins verringert wird.
Wenn der Referenzzähler eines Objekts 0 ist, wird das Objekt freigegeben. Dies ist die grundlegende Referenzzählung.
Für einige Sprachen werden Referenzen automatisch vergrößert und verkleinert, aber Ziel-c ist keine dieser Sprachen. Somit ist der Programmierer für das Beibehalten und Freigeben verantwortlich.
Eine typische Methode zum Schreiben einer Methode ist:
Das Problem, dass Sie daran denken müssen, erworbene Ressourcen innerhalb des Codes freizugeben, ist sowohl mühsam als auch fehleranfällig. Objective-C führt ein weiteres Konzept ein, das dies erheblich vereinfachen soll: Autorelease-Pools. Autorelease-Pools sind spezielle Objekte, die auf jedem Thread installiert werden. Sie sind eine ziemlich einfache Klasse, wenn Sie NSAutoreleasePool nachschlagen.
Wenn an ein Objekt eine "Autorelease" -Nachricht gesendet wird, sucht das Objekt nach Autorelease-Pools, die für diesen aktuellen Thread auf dem Stapel liegen. Das Objekt wird der Liste als Objekt hinzugefügt, an das zu einem späteren Zeitpunkt eine Freigabemeldung gesendet werden soll. Dies ist im Allgemeinen der Fall, wenn der Pool selbst freigegeben wird.
Wenn Sie den obigen Code verwenden, können Sie ihn so umschreiben, dass er kürzer und leichter zu lesen ist, indem Sie sagen:
Da das Objekt automatisch freigegeben wird, müssen wir es nicht mehr explizit als "Freigabe" bezeichnen. Dies liegt daran, dass wir wissen, dass ein Autorelease-Pool dies später für uns erledigt.
Hoffentlich hilft das. Der Wikipedia-Artikel befasst sich ziemlich gut mit Referenzzählung. Weitere Informationen zu Autorelease-Pools finden Sie hier . Beachten Sie außerdem, dass Sie Xcode beim Erstellen für Mac OS X 10.5 und höher anweisen können, mit aktivierter Speicherbereinigung zu erstellen, sodass Sie das Beibehalten / Freigeben / Autorelease vollständig ignorieren können.
quelle
Joshua (# 6591) - Die Garbage Collection in Mac OS X 10.5 scheint ziemlich cool zu sein, ist aber für das iPhone nicht verfügbar (oder wenn Sie möchten, dass Ihre App auf Versionen vor 10.5 von Mac OS X ausgeführt wird).
Wenn Sie eine Bibliothek schreiben oder etwas, das möglicherweise wiederverwendet wird, sperrt die Verwendung des GC-Modus jeden, der den Code verwendet, in die Verwendung des GC-Modus. Soweit ich weiß, tendiert jeder, der versucht, weit wiederverwendbaren Code zu schreiben, dazu, diese zu verwalten Speicher manuell.
quelle
Wie immer, wenn Leute versuchen, das Referenzmaterial neu zu formulieren, verstehen sie fast immer etwas falsch oder liefern eine unvollständige Beschreibung.
Apple bietet eine vollständige Beschreibung des Speicherverwaltungssystems von Cocoa im Programmierhandbuch für die Speicherverwaltung für Cocoa . Am Ende finden Sie eine kurze, aber genaue Zusammenfassung der Speicherverwaltungsregeln .
quelle
Ich werde nicht zu den Besonderheiten der Aufbewahrung / Freigabe hinzufügen, außer dass Sie vielleicht darüber nachdenken möchten, 50 US-Dollar zu verlieren und das Hillegass-Buch zu erhalten, aber ich würde dringend empfehlen, die Tools von Instruments sehr früh in der Entwicklung Ihrer Anwendung zu verwenden (auch Ihre Erster!). Führen Sie dazu Run-> Start with Performance Tools aus. Ich würde mit Leaks beginnen, einem der vielen verfügbaren Instrumente, die Ihnen jedoch zeigen, wenn Sie vergessen haben, sie freizugeben. Es ist ziemlich entmutigend, wie viele Informationen Ihnen präsentiert werden. Schauen Sie sich dieses Tutorial an, um schnell
aufzustehen: COCOA TUTORIAL: BEHEBEN VON SPEICHERLECKEN MIT INSTRUMENTEN
Der Versuch, Lecks zu erzwingen, könnte eine bessere Möglichkeit sein, zu lernen, wie man sie verhindert! Viel Glück ;)
quelle
Autorelease ist nicht behält das Objekt. Autorelease stellt es einfach in die Warteschlange, um es später freizugeben. Sie möchten dort keine Release-Erklärung haben.
quelle
Meine übliche Sammlung von Artikeln zur Speicherverwaltung von Kakao:
Kakao-Speicherverwaltung
quelle
Es gibt einen kostenlosen Screencast vom iDeveloperTV Network
Speicherverwaltung in Objective-C
quelle
Die Antwort von NilObject ist ein guter Anfang. Hier finden Sie einige zusätzliche Informationen zur manuellen Speicherverwaltung ( auf dem iPhone erforderlich ).
Wenn Sie persönlich
alloc/init
ein Objekt haben, wird es mit einem Referenzzähler von 1 geliefert. Sie sind dafür verantwortlich, danach aufzuräumen, wenn es nicht mehr benötigt wird, entweder telefonisch[foo release]
oder telefonisch[foo autorelease]
. Release bereinigt es sofort, während Autorelease das Objekt zum Autorelease-Pool hinzufügt, wodurch es zu einem späteren Zeitpunkt automatisch freigegeben wird.Autorelease ist in erster Linie für den Fall gedacht, dass Sie eine Methode haben, die das betreffende Objekt zurückgeben muss ( Sie können es also nicht manuell freigeben, andernfalls geben Sie ein Null-Objekt zurück ), aber Sie möchten es auch nicht festhalten .
Wenn Sie ein Objekt erwerben, für das Sie nicht alloc / init aufgerufen haben, um es abzurufen - zum Beispiel:
Wenn Sie jedoch an diesem Objekt festhalten möchten, müssen Sie [foo keep] aufrufen. Andernfalls ist es möglich, dass dies der Fall ist
autoreleased
und Sie an einer Null-Referenz festhalten (wie im obigenstringWithString
Beispiel ). Wenn Sie es nicht mehr brauchen, rufen Sie an[foo release]
.quelle
Die obigen Antworten geben klare Anpassungen dessen, was in der Dokumentation steht. Das Problem, auf das die meisten neuen Leute stoßen, sind die undokumentierten Fälle. Beispielsweise:
Autorelease : Dokumente sagen, dass es "irgendwann in der Zukunft" eine Veröffentlichung auslösen wird. WANN?! Grundsätzlich können Sie sich darauf verlassen, dass sich das Objekt in der Nähe befindet, bis Sie Ihren Code wieder in die Systemereignisschleife zurückgeben. Das System kann das Objekt jederzeit nach dem aktuellen Ereigniszyklus freigeben. (Ich denke, Matt hat das früher gesagt.)
Statische Zeichenfolgen :
NSString *foo = @"bar";
- Müssen Sie diese beibehalten oder freigeben? Wie wäre es...
Die Erstellungsregel : Wenn Sie sie erstellt haben, besitzen Sie sie und müssen sie freigeben.
Im Allgemeinen werden neue Cocoa-Programmierer durcheinander gebracht, indem sie nicht verstehen, welche Routinen ein Objekt mit einem zurückgeben
retainCount > 0
.Hier ist ein Ausschnitt aus Very Simple Rules For Memory Management in Cocoa :
Die erste Kugel sagt: Wenn Sie angerufen haben
alloc
(odernew fooCopy
), müssen Sie die Freigabe für dieses Objekt aufrufen.In der zweiten Aufzählung heißt es: Wenn Sie einen Convenience-Konstruktor verwenden und das Objekt herumhängen muss (wie bei einem Bild, das später gezeichnet wird), müssen Sie es beibehalten (und später freigeben).
Der 3. sollte selbsterklärend sein.
quelle
Viele gute Informationen auch über Cocoadev:
quelle
Wie bereits von mehreren Personen erwähnt, ist Apples Einführung in die Speicherverwaltung bei weitem der beste Ausgangspunkt.
Ein nützlicher Link, den ich noch nicht erwähnt habe, ist Practical Memory Management . Sie finden es in der Mitte der Apple-Dokumente, wenn Sie sie durchlesen, aber es lohnt sich, direkt darauf zu verlinken. Es ist eine brillante Zusammenfassung der Speicherverwaltungsregeln mit Beispielen und häufigen Fehlern (im Grunde, was andere Antworten hier zu erklären versuchen, aber nicht so gut).
quelle