< Previous PageNext Page > Hide TOC

Automatic Versus Manual Support

There are two techniques for making a class’s properties observable using key-value observing. Automatic observing is provided by NSObject and is available for all properties of a class that are key-value coding compliant. Manual observing provides additional control over when observations are noted, and requires additional coding.

Contents:

Automatic Key-Value Observing
Manual Observer Notification


Automatic Key-Value Observing

NSObject provides a basic implementation of automatic key-value observing. Using automatic observer notifications, it is not necessary to bracket changes to a property with invocations of willChangeValueForKey: and didChangeValueForKey: when mutating properties via key-value coding and key-value coding compliant methods. Automatic observer notification is controlled by the class method automaticallyNotifiesObserversForKey:. The default implementation returns YES for all keys.

Automatic key-value observing informs observers of changes made using key-value compliant accessors, as well as the key-value coding methods. The examples shown in Listing 1 result in any observers of the property name to be notified of the change.

Listing 1  Methods of invoking key-value observing

// calling the accessor method
[self setName:@"Savings"];
 
// using setValue:forKey:
[self setValue:@"Savings" forKey:@"name"];
 
// using a key path, where account is a kvc-compliant property
// of "document"
[document setValue:@"Savings" forKeyPath:@"account.name"]

Automatic notification is also supported for the collection proxy objects returned by mutableArrayValueForKey: and mutableSetValueForKey: . This works for to-many relationships that support the indexed accessor methods insertObject:in<Key>AtIndex:, replaceObjectIn<Key>AtIndex:, and removeObjectFrom<Key>AtIndex:.

You can control automatic observer notifications for properties of your subclass by implementing the class method automaticallyNotifiesObserversForKey:. Subclasses can test the key passed as the parameter and return YES if automatic notification should be enabled, NO if it should be disabled.

Manual Observer Notification

Manual key-value observer 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 observer notification must override the NSObject implementation of automaticallyNotifiesObserversForKey:. It is possible to use both automatic and manual observer notifications in the same class. For properties that perform manual observer 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 the openingBalance 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 must invoke willChangeValueForKey: before changing the value, and didChangeValueForKey: after changing the value. The example in Listing 3 implements manual observer notifications for the openingBalance property.

Listing 3  Example accessor method implementing manual observer 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.

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 a 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.

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: Care should be taken that you do not release the values that will change, before sending a willChange message.



< Previous PageNext Page > Hide TOC


© 2003, 2009 Apple Inc. All Rights Reserved. (Last updated: 2009-05-06)


Did this document help you?
Yes: Tell us what works for you.
It’s good, but: Report typos, inaccuracies, and so forth.
It wasn’t helpful: Tell us what would have helped.