Speicherverwaltung retain release

  • Speicherverwaltung retain release

    Hallo Forum,

    ich habe eine Frage zur Speicherverwaltung. Wenn ich folgendes mache, warum muss ich nicht currentSelection releasen?

    Quellcode

    1. NSString *currentSelection = [self.pickerData objectAtIndex:currentIndex];


    pickerdata ist ein NSArray mit einem copy "Setter". Macht es überhaupt einen Unterschied wenn ich hier einen copy oder retain "Setter" benutze?

    ---

    Und was ist hiermit:

    Quellcode

    1. self.dataSource = [[NSArray alloc] initWithObjects: @"Luke", @"Leia", @"Han", @"Chewbacca", @"Artoo", @"Threepio", @"Lando", nil];


    Baue ich mir einen Leak auf diese Weise?

    Vielen Dank!

    Gruß
    fin
  • RE: Speicherverwaltung retain release

    Der Zeiger currentSelection verweist auf eine Zeichenkette im Array. Dabei wird aber kein retain auf den String ausgeführt, weswegen ein release auf currentSelection ein Fehler ist. Ein NSArray macht übrigens ein retain auf seine Elemente und gibt sie natürlich im dealloc wieder frei.

    Properties mit dem Attribut copy machen nicht nur einfach ein retain auf das Objekt sondern kopieren es. Nach Aufruf des Setters hat die Propertie ein eigenes Objekt (eine Kopie) des zugewiesenen Objekts. Bei retain gibt's danach nur das eine Objekt.

    Beispiel:

    Quellcode

    1. NSMutableString *theValue = [NSMutableString stringWithCapacity:10];
    2. theObject.property = theValue;
    3. [theValue appendString:@"bla"];
    4. NSLog(@"%@ %@", theValue, theObject.property];

    Wenn die Property den Typ retain hat, erhälst Du bla bla als Ausgabe. Eine Copy-Property liefert Dir hingegen bla. Probier's doch mal aus ;)

    Mit dem zweiten Statement baust Du Dir in der Regel einen Leak. Das muss aber nicht so sein und hängt noch von anderen Code-Teilen ab. Schau doch mal in den Memory Management Guide.
    „Meine Komplikation hatte eine Komplikation.“
  • Hey Danke,

    dann passt es zu dem was ich schon vermutet. Beim Ersten passt es, ich hole mir einen Wert aus dem Array und nicht eine Kopie des Arrays. Deshalb ist es unabhängig ob ich eine copy oder ein retain Setter benutze.
    Somit verweist der currentSelection Zeiger auf die Speicherstelle des ausgewählten Strings im Array. Sobald das Array, aus dem der Wert kommt, sein release erhält (im dealloc) wird es aus dem Speicher entfernt.

    Stimmt doch so, oder?

    Beim Zweiten ist dies der erste Aufruf auf self.dataSource. Wenn es der Erste ist, ist es dann ein Leak? self.dataSource bekommt sein release im dealloc.
    Wenn ich self.dataSource schon initialisiert hätte, hätte ich den Leak, da ich hier ein retain bekommen würde und es nicht wieder runterzähle, oder?

    Gruß
    finarfin
  • Original von finarfin
    Somit verweist der currentSelection Zeiger auf die Speicherstelle des ausgewählten Strings im Array. Sobald das Array, aus dem der Wert kommt, sein release erhält (im dealloc) wird es aus dem Speicher entfernt.

    Stimmt doch so, oder?

    Jo

    Original von finarfin
    Beim Zweiten ist dies der erste Aufruf auf self.dataSource. Wenn es der Erste ist, ist es dann ein Leak? self.dataSource bekommt sein release im dealloc.
    Wenn ich self.dataSource schon initialisiert hätte, hätte ich den Leak, da ich hier ein retain bekommen würde und es nicht wieder runterzähle, oder?

    Das problematische an dem zweiten Statement ist, dass ein mit Alloc-Init konstruiertes Objekt bereits ein Retain erhalten hat. Wenn Deine Property es kopiert, dann kommst Du an das Array nicht mehr dran. Wenn die Property es nur retained, hast Du ein Retain zuviel. Das kannst Du mit autorelease relativ einfach umgehen:

    Quellcode

    1. self.dataSource = [[[NSArray alloc] initWithObjects:...] autorelease];


    Wenn Deine Property den Typ assign hat, ist alles gut, WENN Du in dealloc ein Retain an das Array schickst. Delegates in den Cocoa-Klassen haben (meines Wissens) immer den Typ assign. Das macht auch Sinn, weil sie ja häufig auf self verweisen und da würden retained Properties zu einem Zyklus führen.

    Du solltest Dich immer an die Regeln in dem o. g. Guide halten. Das vereinfacht die Programmierung ungemein ;)
    „Meine Komplikation hatte eine Komplikation.“
  • Meine Property self.dataSource hat einen copy Setter.

    Quellcode

    1. @property (nonatomic, copy) NSArray *dataSource;


    Also wird durch den Aufruf des Setters eine Kopie angelegt vom allocierten Array und in mein dataSource Array gespeichert. Da der Setter eine Kopie macht ist das Array mit dem Alloc nicht erreichbar und kann nicht mehr released werden.

    Also heisst es für mich nun, wenn ich auf autorelease verzichten will:


    Quellcode

    1. NSArray *preDataSource = [[NSArray alloc] initWithObjects: @"Luke", @"Leia", @"Han", @"Chewbacca", @"Artoo", @"Threepio", @"Lando", nil];
    2. self.dataSource = preDataSource;
    3. [preDataSource release];


    Right?

    Gruß
    fin