日期:2011.07.11
<<1.Note-Registering for Key-Value Observing.doc>> <<2.Note-KVO Compliance.doc>>
NextPrevious
http://developer.apple.com/library/ios/documentation/cocoa/conceptual/KeyValueObserving/index.html
Registering for Key-Value Observing
In order to receive key-value observing notifications for a property, three things are required:
- The observed class must be key-value observing compliant for the property that you wish to observe.
- You must register the observing object with the observed object, using the method addObserver:forKeyPath:options:context:.
- The observing class must implement observeValueForKeyPath:ofObject:change:context:.
Important: Not all classes are KVO-compliant for all properties. You can ensure your own classes are KVO-compliant by following the steps described in “KVO Compliance.” Typically properties in Apple-supplied frameworks are only KVO-compliant if they are documented as such.
Registering as an Observer
In order to be notified of changes to a property, an observing object must first register with the object to be observed by sending it an addObserver:forKeyPath:options:context: message, passing the observer object and the key path of the property to be observed. The options parameter specifies the information that is provided to the observer when a change notification is sent. Using the optionNSKeyValueObservingOptionOld specifies that the original object value is provided to the observer as an entry in the change dictionary. Specifying theNSKeyValueObservingOptionNew option provides the new value as an entry in the change dictionary. To receive both values, you would bitwise OR the option constants.
The example in Listing 1 demonstrates registering an inspector object for the propertyopeningBalance.
Listing 1 Registering the inspector as an observer of the openingBalance property
- (void)registerAsObserver
{
/*
Register 'inspector' to receive change notifications for the "openingBalance" property of
the 'account' object and specify that both the old and new values of "openingBalance"
should be provided in the observe… method.
*/
[account addObserver:inspector
forKeyPath:@"openingBalance"
options:(NSKeyValueObservingOptionNew |
NSKeyValueObservingOptionOld)
context:NULL];
}
When you register an object as an observer, you can also provide a context pointer. The context pointer is provided to the observer when observeValueForKeyPath:ofObject:change:context: is invoked. The context pointer can be a C pointer or an object reference. The context pointer can be used as a unique identifier to determine the change that is being observed, or to provide some other data to the observer. The context pointer is not retained, and it is the responsibility of the application to ensure that it is not released before the observing object is removed as an observer.
Note: The key-value observing addObserver:forKeyPath:options:context: method does not retain the observing object or the observed objects. You need to review your application’s requirements and manage retain and release for the observing, and observed, objects.
Receiving Notification of a Change
When the value of an observed property of an object changes, the observer receives anobserveValueForKeyPath:ofObject:change:context: message. All observers must implement this method.
The observer is provided the object and key path that triggered the observer notification, a dictionary containing details about the change, and the context pointer that was provided when the observer was registered.
The change dictionary entry NSKeyValueChangeKindKey provides information about the type of change that occurred. If the value of the observed object has changed, theNSKeyValueChangeKindKey entry returns NSKeyValueChangeSetting. Depending on the options specified when the observer was registered, the NSKeyValueChangeOldKey andNSKeyValueChangeNewKey entries in the change dictionary contain the values of the property before, and after, the change. If the property is an object, the value is provided directly. If the property is a scalar or a C structure, the value is wrapped in an NSValueobject (as with key-value coding).
If the observed property is a to-many relationship, the NSKeyValueChangeKindKey entry also indicates whether objects in the relationship were inserted, removed, or replaced by returning NSKeyValueChangeInsertion, NSKeyValueChangeRemoval, orNSKeyValueChangeReplacement, respectively.
The change dictionary entry for NSKeyValueChangeIndexesKey is an NSIndexSetobject specifying the indexes in the relationship that changed. IfNSKeyValueObservingOptionNew or NSKeyValueObservingOptionOld are specified as options when the observer is registered, the NSKeyValueChangeOldKey andNSKeyValueChangeNewKey entries in the change dictionary are arrays containing the values of the related objects before, and after, the change.
The example in Listing 2 shows the observeValueForKeyPath:ofObject:change:context: implementation for an inspector that reflects the old and new values of the property openingBalance, as registered in Listing 1.
Listing 2 Implementation of observeValueForKeyPath:ofObject:change:context:
- (void)observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object
change:(NSDictionary *)change
context:(void *)context
{
if ([keyPath isEqual:@"openingBalance"]) {
[openingBalanceInspectorField setObjectValue:
[change objectForKey:NSKeyValueChangeNewKey]];
}
/*
Be sure to call the superclass's implementation *if it implements it*.
NSObject does not implement the method.
*/
[super observeValueForKeyPath:keyPath
ofObject:object
change:change
context:context];
}
Removing an Object as an Observer
You remove a key-value observer by sending the observed object aremoveObserver:forKeyPath: message, specifying the observing object and the key path. The example in Listing 3 removes the inspector as an observer of openingBalance.
Listing 3 Removing the inspector as an observer of openingBalance
- (void)unregisterForChangeNotification
{
[observedObject removeObserver:inspector
forKeyPath:@"openingBalance"];
}
If the context specified when the observer was registered is an object, it can be safely released only after removing the observer. After receiving a removeObserver:forKeyPath:message, the observing object will no longer receive any observeValueForKeyPath:ofObject:change:context: messages for the specified key path and object.
NextPrevious
![Picture (Metafile)](https://mail.google.com/mail/u/0/?ui=2&ik=f710b2434e&view=att&th=13116ca1d11eaaff&attid=0.0.1&disp=emb&zw&atsh=1)
© 2003, 2011 Apple Inc. All Rights Reserved. (Last updated: 2011-03-08)
Did this document help you? Yes It's good, but... Not helpful...
Shop the Apple Online Store (1-800-MY-APPLE), visit an Apple Retail Store, or find areseller.
Copyright © 2010 Apple Inc. All rights reserved.
NextPrevious
http://developer.apple.com/library/ios/documentation/cocoa/conceptual/KeyValueObserving/index.html
KVO Compliance
In order to be considered KVO-compliant for a specific property, a class must ensure the following:
There are two techniques for ensuring the change notifications are emitted. Automatic support is provided by NSObject and is by default available for all properties of a class that are key-value coding compliant. Typically, if you follow standard Cocoa coding and naming conventions, you can use automatic change notifications—you don’t have to write any additional code.
Manual change notification provides additional control over when notifications are emitted, and requires additional coding. You can control automatic notifications for properties of your subclass by implementing the class method automaticallyNotifiesObserversForKey:.
[自:2种技术:自动提交和手动提交。]
Automatic Change Notification
[自:这种方法好像是默认的,我没有发现特殊的函数调用来触发自动Notification机制。]
NSObject provides a basic implementation of automatic key-value change notification. Automatic key-value change notification informs observers of changes made using key-value compliant accessors, as well as the key-value coding methods. Automatic notification is also supported by the collection proxy objects returned by, for example,mutableArrayValueForKey:.
The examples shown in Listing 1 result in any observers of the property name to be notified of the change.
Listing 1 Examples of method calls that cause KVO change notifications to be emitted
// Call the accessor method.
[account setName:@"Savings"];
// Use setValue:forKey:.
[account setValue:@"Savings" forKey:@"name"];
// Use a key path, where 'account' is a kvc-compliant property of 'document'.
[document setValue:@"Savings" forKeyPath:@"account.name"];
// Use mutableArrayValueForKey: to retrieve a relationship proxy object.
Transaction *newTransaction = <#Create a new transaction for the account#>;
NSMutableArray *transactions = [account mutableArrayValueForKey:@"transactions"];
[transactions addObject:newTransaction];
Manual Change Notification
Manual change notification provides more granular control over how and when notifications are sent to observers. This can be useful to help minimize triggering notifications that are unnecessary, or to group a number of changes into a single notification.
A class that implements manual notification must override the NSObject implementation ofautomaticallyNotifiesObserversForKey:. It is possible to use both automatic and manual observer notifications in the same class. For properties that perform manual notification, the subclass implementation of automaticallyNotifiesObserversForKey: should return NO. A subclass implementation should invoke super for any unrecognized keys. The example in Listing 2 enables manual notification for theopeningBalance property allowing the superclass to determine the notification for all other keys.
Listing 2 Example implementation of automaticallyNotifiesObserversForKey:
+ (BOOL)automaticallyNotifiesObserversForKey:(NSString *)theKey {
BOOL automatic = NO;
if ([theKey isEqualToString:@"openingBalance"]) {
automatic = NO;
} else {
automatic=[super automaticallyNotifiesObserversForKey:theKey];
}
return automatic;
}
To implement manual observer notification, you invoke willChangeValueForKey: before changing the value, and didChangeValueForKey: after changing the value. The example in Listing 3 implements manual notifications for the openingBalance property.
Listing 3 Example accessor method implementing manual notification
- (void)setOpeningBalance:(double)theBalance {
[self willChangeValueForKey:@"openingBalance"];
openingBalance=theBalance;
[self didChangeValueForKey:@"openingBalance"];
}
You can minimize sending unnecessary notifications by first checking if the value has changed. The example in Listing 4 tests the value of openingBalance and only provides the notification if it has changed.
Listing 4 Testing the value for change before providing notification
- (void)setOpeningBalance:(double)theBalance {
if (theBalance != openingBalance) {
[self willChangeValueForKey:@"openingBalance"];
openingBalance=theBalance;
[self didChangeValueForKey:@"openingBalance"];
}
}
If a single operation causes multiple keys to change you must nest the change notifications as shown in Listing 5.[自:注意:如果是2个以上的变化,则需要使用例子中的方法,而非单独Notification。]
Listing 5 Nesting change notifications for multiple keys
- (void)setOpeningBalance:(double)theBalance {
[self willChangeValueForKey:@"openingBalance"];
[self willChangeValueForKey:@"itemChanged"];
openingBalance=theBalance;
itemChanged=itemChanged+1;
[self didChangeValueForKey:@"itemChanged"];
[self didChangeValueForKey:@"openingBalance"];
}
In the case of an ordered to-many relationship, you must specify not only the key that changed, but also the type of change and the indexes of the objects involved. The type of change is an NSKeyValueChange that specifies NSKeyValueChangeInsertion,NSKeyValueChangeRemoval, or NSKeyValueChangeReplacement. The indexes of the affected objects are passed as an NSIndexSet object.
The code fragment in Listing 6 demonstrates how to wrap a deletion of objects in the to-many relationship transactions.
Listing 6 Implementation of manual observer notification in a to-many relationship
- (void)removeTransactionsAtIndexes:(NSIndexSet *)indexes {
[self willChange:NSKeyValueChangeRemoval
valuesAtIndexes:indexes forKey:@"transactions"];
// remove the transaction objects at the specified indexes here
[self didChange:NSKeyValueChangeRemoval
valuesAtIndexes:indexes forKey:@"transactions"];
}
Note: In a reference counted environment, ou must make sure that you do not release the values that will change before sending a willChange message.
NextPrevious
![Picture (Metafile)](https://mail.google.com/mail/u/0/?ui=2&ik=f710b2434e&view=att&th=13116ca1d11eaaff&attid=0.0.2&disp=emb&zw&atsh=1)
© 2003, 2011 Apple Inc. All Rights Reserved. (Last updated: 2011-03-08)
Did this document help you? Yes It's good, but... Not helpful...
Shop the Apple Online Store (1-800-MY-APPLE), visit an Apple Retail Store, or find areseller.
Copyright © 2010 Apple Inc. All rights reserved.
![Picture (Metafile)](https://mail.google.com/mail/u/0/?ui=2&ik=f710b2434e&view=att&th=13116ca1d11eaaff&attid=0.0.12&disp=emb&zw&atsh=1)
![Picture (Metafile)](https://mail.google.com/mail/u/0/?ui=2&ik=f710b2434e&view=att&th=13116ca1d11eaaff&attid=0.0.22&disp=emb&zw&atsh=1)
+++++