Retain-Count
Das Memory-Management von Cocoa basiert auf einem Retain-Count Mechanismus. Anders als z.B. bei C (malloc & free), gibt es in Objective-C eine klar geregelte Verantwortung für den Lebenszyklus des Objektes:
Ownership
- Wer das Objekt erstellt (also mit alloc Speicher dafür reserviert) =>
- ist der "Creator" und muss die Verantwortung für die Speicherfreigabe übernehmen (also mit release den Speicher wieder freigeben).
Jedes Objekt hat einen sog. retain count, der normalerweise bei der Erstellung des Objektes (z.B. mit alloc oder copy) einen Wert von 1 hat. Wenn nun dieses Objekt von einem anderen Objekt als seinem Eigentümer für längere Berechnungen oder als eigene Instanz-Variable benötigt wird, so kann man [obj retain] aufrufen. Damit steigt der retain-count dieses Objektes um 1 auf 2. Das Objekt wird gelöscht (bzw. der [obj dealloc] aufgerufen), wenn der retain-count auf 0 zurück geht.
Wichtig: Der Programmierer muss dafür sorgen, dass seine retain/release bzw. alloc/release bzw. copy/release Aufrufe ausgeglichen sind. Ansonsten kommt es zu Leaks (Zombie-Objekte) oder zu einem Crash, wenn ein Objekt per release freigegeben wird, das es nicht mehr gibt.
Folgende Aufrufe erfordern einen späteren release
- alloc (owner)
- copy (owner)
- new (owner, selten)
- retain
Alloc/Init/Copy/Retain
NSString *newString = [[NSString alloc] init];
NSString *anotherString = [newString copy];
NSString *aThirdString = [anotherString retain];
- alloc (allocate) reservier Speicher für ein Objekt (und macht sonst nichts weiter, deshalb sieht man alloc immer nur in Verbindung mit init: [[obj alloc] init] oder [[obj alloc] initWithSomething:...]
- alloc erstellt ein Objekt mit einem anfänglichen retain-count von 1
- init (initialize) initialisiert das Objekt
- init erhöht den retain-count nicht!
- copy kopiert das Objekt und erstellt ein neues, eigenständiges Objekt mit einem eigenen Speicherbereich
- copy erstellt ein Objekt mit einem anfänglichen retain-count von 1
- retain sorgt dafür, dass das Objekt auf jeden Fall erhalten bleibt. Es wird kein neues Objekt erstellt.
- retain erhöht den retain-Count um 1.
Beispiel
Interface (file.h)
@interface MyClass:NSObject {
NSString *name;
int age;
id delegate;
}
@property (nonatomic, retain) id delegate;
// Hinweis: name und age würden normalerweise auch einfacher als properties verwendet!
-(NSString*)name;
-(void)setNewName:(NSString*)newName;
-(int)age;
-(void)setAge:(int)newAge;
@end
Implementation (file.m)
#import "file.h"
@implementation MyClass
@synthesize delegate;
-(id)init {
self = [super init];
if(self) {
[self setName:@"Barnie"];
[self setAge:30];
}
}
-(NSString*)name { return name; }
-(void)setName:(NSString*)newName {
if(newName != name) {
[name release];
[newName retain];
name = newName;
}
}
-(int)age { return age; }
-(void)setAge:(int)newAge { age = newAge; }
-(void)dealloc {
[delegate release]; // retain-property!
[self setName:nil]; // release wird im Setter gesendet!
// age braucht keinen release weil int ist kein Objekt!
}
@end
Fragen:
- was ist ein Accessor?
- was passiert im dealloc wenn man schreibt: name = nil;?
- wo ist der Unterschied:
- [self setName:nil];
- self.name = nil;
- name = nil;
Autorelease
...
Regeln
- Genau geregelte Verantwortlichkeiten:
- Wer alloc, new, copy, retain verwendet, muss auch jeweils 1x release senden
- Wer nicht alloc, new, copy, retain aufruft, darf nicht release aufrufen
- Niemals dealloc selbst aufrufen (es sei denn man überschreibt die Methode und ruft [super dealloc] auf!
Links
- Memory Management Programming Guide for Cocoa (Hinweis: iPhone OS bis mind. 3.x hat keinen Garbage Collector!)
Diese Seite ist Teil des Werkmoduls iOS Development von Michael Markert für Interface Design / Fakultät Medien an der Bauhaus-Universität Weimar.