Mit Objective-C Cocoa arbeiten wir mit halbautomatischer Referenzzählspeicherverwaltung. Beim Zuweisen von Speicher für ein Objekt, Beibehalten eines Objekts oder Aufrufen einer copy
-Methode für ein Objekt wird die Retain-Anzahl (Referenzzählung) um 1 erhöht. Beim Aufrufen von release
für ein Objekt wird die Retain-Anzahl um eins verringert. Wenn autorelease
für ein Objekt aufgerufen wird, wird release
zu einem späteren Zeitpunkt (während der Hauptlaufschleife, wenn keiner von Ihrem eigenen Code ausgeführt wird) für das Objekt aufgerufen, so dass es die Referenz nicht wie Sie unter Ihnen herauszieht versuche es zu benutzen). Wenn die Retain-Anzahl 0 erreicht, kann das Objekt freigegeben werden.
Im Allgemeinen, wenn Sie retain
auf ein Objekt anrufen, sind Sie Ihr Interesse an ihm signalisiert, und Sie sind ein release
oder autorelease
Anruf zu einem bestimmten Zeitpunkt für die Herstellung verantwortlich, wenn Sie nicht mehr in dem Objekt interessiert sind . Wenn Sie für ein Objekt die Methode alloc
oder copy
aufrufen, haben Sie Ihr Interesse an dem Objekt signalisiert und müssen es mit einem release
oder autorelease
irgendwo auf der anderen Seite übereinstimmen.
Dieser Link deckt so ziemlich die Richtlinien von Apple verwendet (und Sie sollten verwenden) für die Speicherverwaltung: Simple rules for memory management in Cocoa
der durch die Linie durch den Code Zeile Lassen Sie gehen:
ClassOne *pointer = [[ClassOne alloc]init];
pointer
Punkte auf ein neu zugewiesenes ClassOne-Objekt mit einem Retain-Zählerstand von 1, da wir Alloc darauf aufgerufen haben. Wir sind verpflichtet, die Nummer release
oder autorelease
auf pointer
irgendwann in der Zukunft zu nennen.
ClassTwo *foo = [[ClassTwo alloc]init], *foo2;
foo
Punkte auf ein neu Objekt ClassTwo zugeordnet ist, mit einer Zahl von 1 beibehalten, da wir alloc sie aufgefordert haben. Wir sind verpflichtet, die Nummer release
oder autorelease
auf foo
irgendwann in der Zukunft zu nennen.
foo2
zeigt gerade jetzt nichts besonderes an. Es ist nicht sicher zu benutzen.
foo2 = [foo add: pointer];
pointer
hat foo
hinzugefügt (was immer das bedeutet, wir die Umsetzung nicht kennen). foo
könnte retain
auf pointer
aufgerufen haben, um sein Interesse daran zu signalisieren, und es als Feld hinzugefügt, oder es pointer
zu einer Sammlung hinzugefügt haben (in diesem Fall ist es die Verantwortung der Sammlung retain
darauf, wenn ein Objekt hinzugefügt wird, und release
wenn ein Objekt entfernt wird). In jedem Fall hat dies keine Auswirkungen auf unseren Codeblock. Daher ist es uns egal, was unter der Haube passiert.
Die von dieser Methode zurückgegebene Referenz könnte pointer
selbst sein, oder es könnte eine automatisch freigegebene Kopie von pointer
sein; Wir haben keinen Zugriff auf die API oder die Implementierung, um uns mitzuteilen, welche.
In beiden Fällen ist es nicht unsere Verantwortung, release
für dieses Objekt aufzurufen. Wenn die Methode copy
im Namen oder retain
für die zurückgegebene Referenz (wie foo2 = [[foo add:pointer] retain];
) aufgerufen hätte, wäre die Retain-Zählung um 1 inkrementiert worden, und es wäre in unserer Verantwortung, release
oder autorelease
darauf anzurufen.
[foo release];
Die von foo
referenzierte Objekt freigegeben wurde, was bedeutet, seine Beibehaltungszähler um 1. Für dieses Beispiel verringert wurde, ist dieser Paare mit dem alloc
Anruf wir in Zeile 2 hergestellt, so dass die Zählung behalten wird auf 0 gesetzt, wodurch foo
für die Freigabe freigegeben wird.
Im Allgemeinen ist es uns egal, ob das Objekt freigegeben wurde oder nicht; Wir müssen nur sicherstellen, dass wir alle alloc
, copy
oder retain
Anrufe mit der gleichen Nummer von release
oder autorelease
Anrufe paaren. Wenn wir zu irgendeinem Zeitpunkt ein Interesse an einem Objekt anmelden, liegt es in unserer Verantwortung, unser Interesse freizugeben, andernfalls werden wir Speicherlecks haben.
foo = foo2;
foo
verweist nun auf das gleiche durch foo2
referenzierte Objekt. Denken Sie daran, wir haben keine alloc
oder copy
Methode aufgerufen, als wir foo2
erhielten, noch haben wir ein Interesse daran registriert, indem wir retain
aufrufen. Da wir keine Verantwortung haben, release
unter foo2
anzurufen, sind wir nicht verpflichtet, release
unter foo
anzurufen.
[pointer release];
pointer
‚s behalten Zahl um 1 verringert wurde es im Mai dieses Jahres haben brachte seine Beibehaltungszähler auf 0 oder nicht, es hängt davon ab, welche foo
tat, als wir es hinzugefügt. Trotzdem ist uns das egal. Wir haben unsere Verantwortung zu pointer
beendet, indem wir release
darauf anrufen, um mit dem alloc
Anruf übereinzustimmen, den wir am Anfang bildeten. Obwohl pointer
nach diesem Aufruf möglicherweise noch vorhanden ist, können wir diese Annahme nicht machen, und alles mit dem zuvor durch Zeiger referenzierten Objekt zu tun, wäre ein Fehler (obwohl wir pointer
ändern könnten, um auf etwas anderes frei zu zeigen).
[foo release];
Wenn der Autor dieses Codes hat die Speicherverwaltung Konventionen des verfolge Apfels, dann ist dies nicht notwendig. Wir haben keine Verantwortung, release
auf foo
oder foo2
aufzurufen (sie verweisen auf das gleiche Objekt, nicht vergessen). Dies führt nicht zum Bruch des Codes. etwas auf eine nil
Referenz zu nennen ist im Wesentlichen ein No-Op. Es kann jedoch für jeden, der den Code überprüft, Verwirrung stiften.
Nun, der Autor dieses Codes möglicherweise die Speicherverwaltung Konventionen gebrochen. Er könnte dafür gesorgt haben, dass add
Anruf eine Kopie von pointer
ohne Anruf autorelease
darauf zurückgibt, in diesem Fall macht es den Anrufer verantwortlich für den Anruf release
darauf. Dies ist eine sehr schlechte Form, und wenn Sie Code ausführen sollten, der die Speicherverwaltungskonvention durchbricht, dokumentieren Sie, wo Sie ihn verwenden und wie er die Konvention bricht, um in Zukunft Verwirrung zu vermeiden.
Wie lauten die Klassennamen dieser Klassen? –
Übrigens bin ich nicht sicher, ob dies im Prozess der Anonymisierung des Codes oder was geschah, aber dieser Code ist ziemlich verwirrend, wenn man bedenkt, dass er nur sieben Zeilen umfasst. – Chuck