views:

34

answers:

3

Lets say I have a simple object that represents the state of a puzzle. The puzzle can be either solved or unsolved. I have two controllers with references to this puzzle object and they are visually representing the state in two different ways - say an on/off switch and a red/green light.

When the 'solved' property of the puzzle changes, the controllers need to update their view to represent the current state. Is there a standard idiom for communication the state change from the puzzle object to the controller?

My initial intent was to declare a custom protocol and track observers in the puzzle object. When the solved property changed, iterate over all the observers and invoke a specific method on the protocol. This seems like a common enough pattern that there might be some built in support but I wasn't able to find exactly what I was looking for in the docs.

+1  A: 

If I'm understanding correctly you can use NSNotification to do what you want. In your puzzle class you can use postNotificationName to tell any class that's observing when the puzzle changes state. To register a class as an observer to the puzzle, use the addObserver and removeObserver methods. Here are the definitions for the three methods:

-(void) postNotificationName:(NSString *) aName object:(id)anObject userInfo:(NSDictionary *)aUserInfo;
-(void) addObserver:(id)observer selector:(SEL)aSelector name:(NSString *)aName object:(id)anObject;
-(void) removeObserver:(id)observer name:(NSString *)aName object:(id)anObject;

Here is some example code to use these for your program:

In your puzzle class, in the function that changes state:

[[NSNotificationCenter defaultCenter] postNotificationName:@"puzzleChangedState" object:self userInfo:NULL]
// if you want to send out moreInfo, like other variables, use userInfo with a dictionary object

In your controllers, or views, etc... wherever you want to get the puzzle changed state message:

//In your constructor or initialization method, register this class with the puzzle class
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handlePuzzleChangedState:) name:@"puzzleChangedState" object:nil];

This will add your controller to the NotificationCenter and when the puzzle class posts a notification of "puzzleChangedState", your controller's handlePuzzleChangedState: method will be invoked.

Here is the handlePuzzleChangedState: function:

-(void) handlePuzzleChangedState:(NSNotification *) notification
{
    //handle your puzzle state change here
}

If you want more help here's the docs: http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/Notifications/Introduction/introNotifications.html#//apple_ref/doc/uid/10000043i

Hope it works out!

programmerdave
A: 

Instead of a custom protocol, you can use notifications as follows. In your controller, in viewDidLoad register yourself as an observer

[[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(puzzleStateDidChange:)
                                                 name:@"PuzzleStateDidChange" object:nil];

then implement

- (void)puzzleStateDidChange:(NSNotification *)notification
{

// set your switch and light according to the state notified
puzzleState = notification.object;
...

}

and finally add

[[NSNotificationCenter defaultCenter] removeObserver:self];

to the dealloc method to unregister yourself as an observer.

Now you are ready to receive notifications and react accordingly. What is missing is the code to be added to your puzzle object. Each time the state changes in the puzzle object,

use something like

[[NSNotificationCenter defaultCenter] postNotificationName:@"PuzzleStateDidChange" object:yourPuzzleState];

to notify your controllers about the state change.

unforgiven
+2  A: 

While both answers so far have concentrated on the use of NSNotification, and that's totally valid, there's another way to do what you want that's built-in to Cocoa objects: Key-Value Observing, or KVO. It's slightly lighter-weight and a little less "action at a distance". I prefer using it whenever possible for observing changes in my data model classes. YMMV.

Shaggy Frog