ObjectiveCeeds › Objective-C: Speicherverwaltung zu Fuß

Objective-C: Speicherverwaltung zu Fuß

Von Manfred Kreß
Die erste Anwendung
Seite 4 von 6



Zeit die Klasse anzuwenden. OCPet ist eine neue Klasse, die Daten eines Haustiers speichert. Name und Art des Haustiers werden als OCString gespeichert. OCPet.h
//
//  BAPet.h
//  RetainCount
//
#import <stdio.h>

#import "OCObject.h"
#import "OCString.h"

/*
	Just an example
*/

@interface OCPet : OCObject {
	OCString *_OCName;
	OCString *_OCKind;
}

- (void) setName: (OCString *)value;
- (OCString *)name;

- (void) setKind: (OCString *)value;
- (OCString *) kind;

// dump to console
- (void) dump;

@end
Das Interface sollte selbst erklärend sein. Interessanter ist die Implementation, da hier zum ersten mal der retain/release Zyklus zur Anwendung kommt.
//
//
//  BAPet.m
//  RetainCount
//

#import "OCPet.h"

@implementation OCPet

- (id) init
{
	self = [super init];
	if (self != nil) {

		OCString *name = [[OCString alloc] init];
		OCString *kind = [[OCString alloc] init];

		[self setName: name];
		[self setKind: kind];

		[name release];
		[kind release];
	}
	return self;
}

- (void) cleanup
{
	[self setName: nil];
	[self setKind: nil];

	[super cleanup];
}

- (void) setName: (OCString *)value
{
	[value retain];		// retain the new one
	[_OCName release];  // release the old one
	_OCName = value;	// assign
}

- (OCString *) name
{
	return _OCName;
}

- (void) setKind: (OCString *)value
{
	[value retain];		// retain the new one
	[_OCKind release];  // release the old one
	_OCKind = value;	// assign
}

- (OCString *)kind
{
	return _OCKind;
}

- (void) dump
{
	OCString *oName = [self name];
	OCString *oKind = [self kind];

	char *cName = [oName cString];
	char *cKind = [oKind cString];

	printf("Name: %s Art: %s\n" , cName , cKind);
}
@end
Werfen wir zunächst ein Blick auf den Setter setName:
- (void) setName: (OCString *)value
{
	[value retain];		// retain the new one
	[_OCName release];  // release the old one
	_OCName = value;	// assign
}
_OCName, also der String der gerade gespeichert ist bekommt ein release geschickt. Wir haben kein Interesse mehr an diesem Objekt. Der Retaincount wird um eins erniedrigt. value dagegen bekommt ein retain geschickt, da wir einen Zeiger darauf behalten wollen. Zum Schluß wird _OCName noch der Zeiger des neuen Objekts zugewiesen. Nach diesem Standardmuster wird in Zukunft jeder Zeiger auf ein Objekt übergeben, also analog auch setKind:. Die Initialisierung:
- (id) init
{
	self = [super init];
	if (self != nil) {

		OCString *name = [[OCString alloc] init];
		OCString *kind = [[OCString alloc] init];

		[self setName: name];
		[self setKind: kind];

		[name release];
		[kind release];
	}
	return self;
}
Standardmäßig wird super initialisiert und self zugewiesen. Es folgt die Initialisierung der Standardwerte des neuen Objekts (leere Strings). Die Strings werden jeweils allociert und initialisiert, danach mit self setXY übergeben und dann released. Werfen wir mal einen Blick auf die Retaincounts dieser Strings am Beispiel des Namens:
  • OCString *name = [[OCString alloc] init]; - ein neu initialisiertes Objekt hat eine Retaincount von 1: RC=1
  • [self setName: name]; - der Setter released das vorhandene Objekt (hier nil) und schickt name ein retain: RC=2
  • [name release]; - name wird hier nicht mehr gebraucht, der Retaincount um 1 erniedrigt: RC=1
Die Instanzobjekte haben also einen Retaincount von 1. Und nun cleanup
- (void) cleanup
{
	[self setName: nil];
	[self setKind: nil];

	[super cleanup];
}
Jede Instanzvariable wird auf nil gesetzt und danach wird cleanup an super weitergeleitet. Werfen wir noch einmal einen Blick auf die Instanzvariablen am Beispiel des Namens. -Nach der Initialisierung hatten die Instanzobjekte einen Retaincount von 1: RC=1 - [self setName: nil]; - durch den Zugriff über den Setter bekommt _OCName ein release: RC=0 _OCName triggert damit seine eigene cleanup Methode, welche hier wiederum an super -OCObject- weitergeleitet wird und Object ruft schließlich free auf - der Speicher von _OCName ist freigegeben!
  • Der Setter weist _OCObject nil zu.
  • Schließlich wird noch ein cleanup an die eigene Superinstanz geschickt, auch OCObject, welche dann wieder free aufruft.

« vorige Seitenächste Seite »