Key-Value-Coding ist ein elementares und grundlegendes Design-Pattern von Cocoa.

Accessors

Im Prinzip ist damit ein System von Accessoren gemeint. Am Beispiel wird das einfach deutlich. Nehmen wir an, eine Klasse hat eine iVar (Instanzvariable) und Property "NSString* myName":

In Cocoa wird üblicherweise außerhalb der Klasse niemals direkt auf eine Instanzvariable zugegriffen. Jede Klasse stellt hierfür sogenannte Accessoren zur Verfügung, also jeweils eine Getter- und eine Setter-Methode, z.B.:

-(NSString*)name { return name; }
-(void)setName:(NSString*)newName {
    if(newName != name) {
        [name release];
        name = [newName copy];
    }
}

@Properties = Accessors

Der Einsatz von Properties erleichtert lediglich das Tippen, da hiermit die Accessoren beim Kompilieren automatisch erstellt werden:

// MyFile.h
@property(nonatomic, copy) NSString* name;
// MyFile.m
@synthesize name;

Durch @synthesize werden also die beiden o.g. Methoden generiert und dabei auf das Memory Management Rücksicht genommen.

Using Accessors

Gibt es diese Accessoren, können die Werte wie folgt gelesen/gesetzt werden. Jede dieser Methoden (außer die letzte) ist gültig und macht exakt das Gleiche:

// getter
NSString *myString;
myString = [self name];
myString = [self valueForKey:@"name"];
myString = self.name;
myString = name; // ACHTUNG: hier wird direkt auf die iVar und nicht auf den Getter zugegriffen!!!

// setter
[self setName:@"Test"];
[self setValue:@"Test" forKey:@"name"];
self.name = @"Test";
name = @"Test"; // ACHTUNG: hier wird direkt auf die iVar und nicht auf den Setter zugegriffen!!!

Man beachte, dass die mit "ACHTUNG" versehenen Zeilen nicht auf die Getter/Setter, sondern direkt auf die Instanzvariablen zugreifen. Damit wird u.a. auch das Memory Management (retain/release-Zyklen) umgangen, was natürlich schlecht ist ;-)

Key/Value

Key-Value-Coding meint also ganz allgemein, das Zur-Verfügung-Stellen von Accessoren für Properties. Anders ausgedrückt, hat die Klasse verschiedene Eigenschaften ("Properties"), auf deren Werte ("Values") man mit Schlüsselwörtern ("Keys") zugreifen kann. Oder einfacher: jede Property kann mit einem valueForKey: und setValue:forKey: Selektor adressiert werden, ohne dass man die Klasse, mit der man kommuniziert, importieren muss.

// ohne key-value coding:
NSString* myString = [myObject name];
[myObject setName:@"Hallo Welt"];

// mit key-value coding:
NSString* myString = [myObject valueForKey:@"name"];
[myObject setValue:@"Hallo Welt" forKey:@"name"];

// collections benutzen Key-Value-Coding
NSNumber* myNumber = [myDict valueForKey:@"myNumber"];
[myDict setValue:[NSNumber numberWithInt:5] forKey:@"myNumber"];


Vorteile von Key-Value-Coding

  • Keine benannten Selektoren (nur valueForKey: und setValue:forKey:)
  • Sämtliche Cocoa-Collections (NSArray, NSDictionary...) benutzen KVC[[KVC+KVO|Key-Value-Coding]]
  • Bindings (nicht verfügbar in iPhone OSOperating System – for instance Apple's OS X stands for the tenth version of the OS <= 3.0) funktionieren mit KVC[[KVC+KVO|Key-Value-Coding]]
  • Ideal für dynamisch synthetisierte Methoden

Key-Value-Observing

KVO[[KVC+KVO|Key-Value-Observing]] (Key-Value-Observing) ist ein sehr schlaues Konzept zur Beobachtung von geänderten Properties. Das Funktionsprinzip ist einfach:

  • Registrieren, um Benachrichtigungen bei Änderungen von Properties zu erhalten
  • Methode überschreiben, die den Empfang von Nachrichten bei Änderungen erlaubt
  • Registrierung entfernen, wenn keine Beobachtung mehr erwünscht ist
// register for KVO (eg. in -viewDidLoad:)
[model addObserver:self
	    forKeyPath:@"propertyName"
	       options:NSKeyValueObservingOptionNew
	       context:NULL];

// implement this method to receive notifications
-(void)observeValueForKeyPath:(NSString *)keyPath
		     ofObject:(id)object
		       change:(NSDictionary *)change
		      context:(void *)context 
{
	NSLog(@"Property changed: %@", object);
}

// remove observer when done (eg. in -dealloc)
[model removeObserver:self forKeyPath:@"propertyName"];

Vorteile von Key-Value-Observing

  • Keine Referenz vom Model zum Controller: Der Controller kann Änderungen im Model registrieren, ohne dass das Model eine explizite Referenz zum Controller halten muss
  • Vermeiden von unerwünschten Schleifen beim Aktualisieren von Werten

Links



Diese Seite ist Teil des Werkmoduls iOS Development von Michael Markert für Interface Design / Fakultät Medien an der Bauhaus-Universität Weimar.