retain und release: Hä?

Kümmelkorn

Kümmelkorn

Aktives Mitglied
Thread Starter
Dabei seit
06.10.2008
Beiträge
1.941
Reaktionspunkte
127
Hallo,

ich versuch gerade, mich in Objetive C & Cocoa einzuarbeiten und stoße dabei beim Speichermanagment auf Verständnisprobleme.. Liegt wohl daran, dass ich bisher wenn überhaupt hauptsächlich mit PHP „programmiert“ habe und mich daher noch nie mit Speichermanagment beschäftigt habe.

In dem Wikibook, dass ich verwende, wird eine Klasse geschrieben (für ein CustomView - sie malt nur Text auf das CustomView, nichts schwieriges). Dabei gibt es eine Methode setText, um den Text festzulegen, der ins CustomView gemalt werden soll:

Code:
- (void)		setText:(NSString*) text withSize:(int) size
 {
	[text retain];
	[_text release];
	_text = text;
	_size = size;
	[self setNeedsDisplay:YES];
 }

_text ist eine Variable der Klasse, sollte ja recht klar sein.

Worüber ich mir gerade den Kopf zerbreche, ist folgendes:
  1. _text soll released werden, damit es leer ist und im nächsten Schritt überschrieben werden kann - warum muss man etwas, was sowieso überschrieben wird erst noch leer machen? Ist das nur für den Fall, dass der Wert zum Überschreiben (text) weniger Bits hat als der zu überschreibenden Wert (_text)?
  2. „retain before release“ leuchtet ja noch ein mit der Erklärung, die ich gelesen habe, aber wenn ich text nun retained habe, warum muss ich es am Ende der Funktion nicht releasen? Mache ich durch retain nicht aus dem text so eine Art globales Zeugs, was auch nach Ende der Funktion noch existiert?

Danke im vorraus :)
Gruß, Micha
 
Hi,

gleich vorweg - denke darüber nach, Dir ein Buch mit was Einführendem zu kaufen. Die Speicherverwaltung ist ein elementarer Teil von Cocoa und sollte gut verstanden werden. In diesem Unterforum gibt es Hinweise auf Bücher.

Darüber hinaus ist das:
http://developer.apple.com/document.../MemoryMgmt.html#//apple_ref/doc/uid/10000011
und das:
http://developer.apple.com/document...mentals/Introduction/chapter_1_section_1.html
Pflichtlektüre...

Zu Deiner Frage:

Cocoa arbeitet bei der Speicherverwaltung mit Referencecounting (benutze den englischen Begriff), wird ein Objekt mit alloc erzeugt, hat der Zähler den Wert 1. Mit retain wird dieser Zähler um eins erhöht, mit release wird der Zähler um 1 verringert. Erreicht der Zähler 0, wird das Objekt freigegeben.

Grundsätzlich sollte man alle Eigenschaften eines Objektes in sog. Accessoren kapseln und der Zugriff auf Instanzvariablen nur hierüber erfolgen.

Aber Du solltest auf jeden Fall was einführendes lesen.

Beste Grüße, SMJ


P.S.: Dieses Buch behandelt gerade die Speicherverwaltung sehr Anfängertauglich und gründlich:

http://www.amazon.de/Objective-C-Co...=sr_1_1?ie=UTF8&s=books&qid=1234442145&sr=8-1
 
Hey,

bin kein ObjectiveC Guru, aber ich denk ich kanns einigermaßen erklären:

_test ist nicht das Objekt selbst, sondern nur die Referenz darauf. [_test retain] ändert aber den Referenzzähler des Objektes (Referenzen haben keine Referenzzähler).
Mit _test = test überschreibst du die Referenz, nicht das Objekt. _test zeigt danach halt auf eine anderes Objekt.
_test ist außerdem eine Instanzvariable (nehm ich mal an), also ist sie global für alle Methoden dieser Instanz des Objektes verfügbar. Das muss sie auch sein, weil die Paint Methode (oder wie auch immer das bei ObjetiveC heißt) ja auch zugriff darauf haben muss im den String malen zu können.

Zur Methode:
Als allererstes sagst du als erstmal, dass du das neue test behalten willst, also rufst du sofort retain auf, damit nicht zufällig der Garbage Collector auf die Idee kommt das wegzuräumen.
Danach gibts du das alte NSString Objekt frei (du hast ja irgendwann als du es erstellt oder übergeben hast da auch ein retain drauf aufgerufen... jetzt gibts du es so zu sagen zurück)
Danach biegst du nur noch die Referenz um, so das sie auf das gleiche Objekt zeigt wie der test Pointer.

Für _size brauchst das ganze dann nicht machen, weil das is ja nur ein primitive Type, kein Objekt.

Hoffe das war einigermaßen hilfreich.
 
  • Gefällt mir
Reaktionen: Kümmelkorn
Du hast recht, wenn du sagst, dass hier das verwiesene Objekt überlebt. Das soll es ja auch! Du verweist schließlich darauf.

Es ist kein Memory-Leak, weil das verweisene Objekt (also das mit der Instanzvariable) den Verweis in -dealloc entfernt, wenn es selbst gelöscht wird.
 
  • Gefällt mir
Reaktionen: Kümmelkorn
Danke schon mal für die Antworten, ich glaube, ich komme langsam dahinter - Referenz war ein gutes Stichword: Was passiert eigentlich in dieser Codezeile genau?
Code:
_text = text;

Wenn ich das nun richtig verstanden hab, wird also gar nicht der komplette Inhalt von text kopiert und neu in _text gespeichert (so dachte ich bisher), sondern das eigentliche Objekt bleibt einfach dort im Speicher, wo es ist und _text bekommt die Adresse von text zugewiesen, richtig?
 
richtig
 
  • Gefällt mir
Reaktionen: Kümmelkorn
Code:
_text = text;

Wenn ich das nun richtig verstanden hab, wird also gar nicht der komplette Inhalt von text kopiert und neu in _text gespeichert (so dachte ich bisher), sondern das eigentliche Objekt bleibt einfach dort im Speicher, wo es ist und _text bekommt die Adresse von text zugewiesen, richtig?

Richtig, allerdings ist diese Art der Implementierung gefährlich.

Bei manueller Speicherverwaltung (ohne g.c.) macht man es z.B.so:
Code:
-(void)setText:(NSString*)text
{
    // Test auf selbstzuweisung
    if ( _text != text ) {
         // altes Objekt freigeben
         [ _text release ];
         // neue Referenz von Text mit erhöhtem Referenzzähler speichern
        _text = [ text retain ];
    }
}
Gruß SMJ
 
Zuletzt bearbeitet:
Den Begriff managed env. verwendet Apple selber in der doku, habs der besseren Anfänger-verständlichkeit zuliebe geändert.
 
Mal abgesehen davon, dass es bei GC kein -retain gibt. ;-) Du vermischst hier zwei Speicherverwaltungssysteme.

Ja gut, habs falsch bezeichnet... tatsache ist aber, das irgendwer das Objekt löscht wenn retain wenn der refcount auf 0 ist... der einzige unterschied ist, dass der Entwickler bei echtem GC nicht selbst die Referenzen zählen muss.
 
Was passiert eigentlich in dieser Codezeile genau?
Code:
_text = text;

Wenn ich das nun richtig verstanden hab, wird also gar nicht der komplette Inhalt von text kopiert und neu in _text gespeichert (so dachte ich bisher), sondern das eigentliche Objekt bleibt einfach dort im Speicher, wo es ist und _text bekommt die Adresse von text zugewiesen, richtig?

Stimmt.

Kurz gesagt: du arbeitest mit Zeigern, also nicht mit den eigentlichen Daten. So ähnlich wie eine Verknüpfung auf dem Desktop.
Um bei diesem Beispiel zu bleiben: Du hast z.B. am Desktop eine Verknüpfung auf ein Dokument. Jetzt bekommst du aber eine neuere Version des Dokuments von einem Kollegen und speicherst diese ab. Du löscht also das alte Dokument und sagst der Verknüpfung, wo sie das neue Dokument findet.

in der Analogie:
[text retain]; 'sichert' dir das neue Dokument
[_text release]; löscht das alte Dokument (nur die Daten, nicht die Verknüpfung, die bleibt)
_text = text; leitet die bestehende Verknüpfung um

Jetzt kannst du dir denken, was passiert, wenn man mit Zeigern nicht richtig arbeitet:
kein release - Das alte Dokument bleibt erhalten, aber nicht zugreifbar -> Speicherleck
kein retain - Dokument wird gelöscht werden, obwohl nicht beabsichtigt -> Pointer zeigt auf ungültige Daten, ev. Speicherzugrifffehler
 
  • Gefällt mir
Reaktionen: Kümmelkorn
managed:
In Bezug auf die Setter? Kannst du das mal verlinken?
 
Ja gut, habs falsch bezeichnet... tatsache ist aber, das irgendwer das Objekt löscht wenn retain wenn der refcount auf 0 ist... der einzige unterschied ist, dass der Entwickler bei echtem GC nicht selbst die Referenzen zählen muss.
Der Unterschied ist, dass bei GC dire Löschung asynchron erfolgt.
 
Wenn ich das nun richtig verstanden hab, wird also gar nicht der komplette Inhalt von text kopiert und neu in _text gespeichert (so dachte ich bisher), sondern das eigentliche Objekt bleibt einfach dort im Speicher, wo es ist und _text bekommt die Adresse von text zugewiesen, richtig?
Ja, genau dasselbe passiert übrigens auch in PHP >= 5, wenn du mit Objekten arbeitest.
 
managed:
In Bezug auf die Setter? Kannst du das mal verlinken?

Hi Amin, kann es gerade nicht verlinken, bin nur mit dem handy im Netz-steht aber z.Bsp. häufig im Cocoa Fundamentals guide:
Sektion basic subclass Design
"if the garbage collector ist enabled, the implementation of accessor methods ist much simpler than in memory-managed code..."

Auch in der property-doku findest du den Begriff.

Gruß SMJ
 
Hi Amin, kann es gerade nicht verlinken, bin nur mit dem handy im Netz-steht aber z.Bsp. häufig im Cocoa Fundamentals guide:
Sektion basic subclass Design
"if the garbage collector ist enabled, the implementation of accessor methods ist much simpler than in memory-managed code..."

Auch in der property-doku findest du den Begriff.

Gruß SMJ
Ach, du meintest Memory-Management. Ich dachte in Object-Management.

Aber auch da ist es so, dass die beiden oben zitierten Setter gleichwertig sind. Bei GC benötigst du überhaupt nur eine Zuweisung, also einen Assign-Setter.
 
Zurück
Oben Unten