emailconfirmed, nsInternRO, nsInternRW, Administrators
3,356
edits
|  (created) |  (added KVO) | ||
| (4 intermediate revisions by the same user not shown) | |||
| Line 1: | Line 1: | ||
| Key-Value-Coding ist ein elementares und grundlegendes Design-Pattern von Cocoa: | 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 "<tt>NSString* myName</tt>": | |||
| 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.: | |||
| <source lang="objc"> | |||
| -(NSString*)name { return name; } | |||
| -(void)setName:(NSString*)newName { | |||
|     if(newName != name) { | |||
|         [name release]; | |||
|         name = [newName copy]; | |||
|     } | |||
| } | |||
| </source> | |||
| == @Properties = Accessors == | |||
| Der Einsatz von Properties erleichtert lediglich das Tippen, da hiermit die Accessoren beim Kompilieren automatisch erstellt werden: | |||
| <source lang="objc"> | |||
| // MyFile.h | |||
| @property(nonatomic, copy) NSString* name; | |||
| // MyFile.m | |||
| @synthesize name; | |||
| </source> | |||
| 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: | |||
| <source lang="objc"> | |||
| // 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!!!  | |||
| </source> | |||
| 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.  | |||
| <source lang="objc"> | <source lang="objc"> | ||
| Line 16: | Line 65: | ||
| Vorteile von Key-Value-Coding | == Vorteile von Key-Value-Coding == | ||
| * Keine benannten Selektoren (nur valueForKey: und setValue:forKey:) | * Keine benannten Selektoren (nur valueForKey: und setValue:forKey:) | ||
| * Sämtliche Cocoa-Collections (NSArray, NSDictionary...) benutzen KVC | * Sämtliche Cocoa-Collections (NSArray, NSDictionary...) benutzen KVC | ||
| Line 22: | Line 71: | ||
| * Ideal für dynamisch synthetisierte Methoden | * Ideal für dynamisch synthetisierte Methoden | ||
| == Key-Value-Observing == | |||
| KVO (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 | |||
| <source lang="ObjC"> | |||
| // 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"]; | |||
| </source> | |||
| == 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 == | == Links == | ||