Downloads
Notification - complete example.
Resources
Chapter 14 of Cocoa Programming text.
Overview
The MVC discussion introduced programmer defined
notifications to illustrate the mechanism.
Notification is part of the API, simple and intuitive to use; once the
notification concept is understood.
The key concept is that of a notification center that handles:
- adding observers
- notifying observers
- removing observers

Example
The following example illustrates sending a "Hello World" string through
a notification.
- NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
the notification object.
- [nc addObserver: model1
selector: @selector(input:)
name: @"BUTTONCHANGE"
object: nil];
Adds model1 object as an observer of @"BUTTONCHANGE".
Select that all @"BUTTONCHANGE" notifications sent to
input: Model1 method.
- [nc postNotificationName: @"BUTTONCHANGE"
object: @"Hello World"];
Notify all observers of @"BUTTONCHANGE".
Send to message selected (i.e. input:) @"Hello World".
- (void) input: (NSNotification *) notification {
NSString * title = (NSString *)[ notification object ];
Receive notification object.
Cast as string.
HelloWorld.m
model1 = [Model1 new];
NSNotificationCenter *nc =
[NSNotificationCenter defaultCenter];
[nc addObserver: model1
selector: @selector(input:)
name: @"BUTTONCHANGE"
object: nil];
[nc postNotificationName: @"BUTTONCHANGE"
object: @"Hello World"];
[nc removeObserver: model1];
|
|
Model1.m
-(void) input: (NSNotification *) notification {
NSString * title = (NSString *)[ notification object ];
NSLog(@" %@ ", title );
} |
|
Example
Another calculator implementation. This demonstrates the use of
notifications to further decouple components.
The key idea is for only the controller to have any knowledge of the
other components, the Model1, Model2, and View. Data passes between each
exclusively through notifications.
You may recall the MVC example in which Model1 held a reference to a View
object, theDisplay, and Model2 to theCount. This coupled the
Model-View-Controller more closely than necessary (i.e. the models had to
know about UITextBox'es) and created a convoluted MVC relationship
(upper-right).
The example above illustrated the ViewController notifying Model1 of a @"BUTTONCHANGE".
This example adds Model1 and Model2 notifying ViewController, decoupling
the reference to a UITextBox object, producing the typical MVC relationship
depicted lower-right.
Three different notifications are used:
- @"BUTTONCHANGE" to notify Model1 and Model2 objects of a button
change and the button pressed.
- @"ACCUMULATORCHANGE" to notify ViewController object of an
accumulator change and its value.
- @"COUNTCHANGE" to notify ViewController object of a count change and
its value.
CalculatorAppViewController.m
#import "CalculatorAppViewController.h"
@implementation CalculatorAppViewController
- (void)viewDidLoad {
[super viewDidLoad];
model1 = [Model1 new];
model2 = [Model2 new];
NSNotificationCenter *nc =
[NSNotificationCenter defaultCenter];
[nc addObserver: model1
selector: @selector(input:)
name: @"BUTTONCHANGE"
object: nil];
[nc addObserver: model2
selector: @selector(input:)
name: @"BUTTONCHANGE"
object: nil];
[nc addObserver: self
selector: @selector(count:)
name: @"COUNTCHANGE"
object: nil];
[nc addObserver: self
selector: @selector(accumulator:)
name: @"ACCUMULATORCHANGE"
object: nil];
}
-(IBAction) input: (id) sender {
UIButton *uiButton = (UIButton *) sender;
NSString *title = uiButton.currentTitle;
NSNotificationCenter *nc =
[NSNotificationCenter
defaultCenter];
[nc postNotificationName: @"BUTTONCHANGE"
object: title];
}
-(void) accumulator: (NSNotification *) notification {
theDisplay.text = (NSString *) [notification object];
}
-(void) count: (NSNotification *) notification {
theCount.text = (NSString *) [notification object];
}
- (void)dealloc {
NSNotificationCenter *nc =
[NSNotificationCenter defaultCenter];
[nc removeObserver: model1];
[nc removeObserver: model2];
[nc removeObserver: self];
[model1 release];
[model2 release];
[super dealloc];
}
@end
|
|
Model1.m
#import "Model1.h"
@implementation Model1
-(void) input: (NSNotification *) notification {
NSString * title = (NSString *)[ notification object ];
char c = [title characterAtIndex: (NSInteger) 0];
switch (c) {
case '=' : [self equal]; break;
case '+' : case '-' : case '*': case '/' :
operation = c;
operand = accumulator;
accumulator = 0.0;
break;
case 'R' : operation = c; accumulator = 0;
operand = '\0';
break;
default : accumulator = accumulator *
10+(int)c-48;
}
NSString *s =
[[NSString alloc]
initWithFormat: @"%f", accumulator];
[[NSNotificationCenter defaultCenter]
postNotificationName:@"ACCUMULATORCHANGE"
object: s];
[s autorelease];
}
-(void) equal {
switch (operation) {
case '+' : accumulator = operand + accumulator;
break;
case '-' : accumulator = operand - accumulator;
break;
case '*' : accumulator = operand * accumulator;
break;
case '/' : accumulator = operand / accumulator;
break;
}
}
-(id) init {
[super init];
accumulator=0.0;
operand='\0';
return self;
}
@end |
Model2.m
#import "Model2.h"
@implementation Model2
-(id) init {
[super init];
count = 0;
return self;
}
-(void) input: (NSNotification *) title {
count++;
NSString *s =
[[NSString alloc] initWithFormat:
@"%3.0f", (double)count];
[[NSNotificationCenter defaultCenter]
postNotificationName:@"COUNTCHANGE"
object: s];
[s autorelease];
}
@end |
|
CalculatorAppViewController.h
#import <UIKit/UIKit.h>
#import "Model1.h"
#import "Model2.h"
@interface CalculatorAppViewController : UIViewController {
IBOutlet UITextField *theDisplay;
IBOutlet UITextField *theCount;
Model1 *model1;
Model2 *model2;
}
-(IBAction) input: (id) sender;
@end |
|
Model2.h
#import <Foundation/Foundation.h>
@interface Model2 : NSObject {
int count;
}
-(void) input: (NSNotification *) title;
-(id) init;
@end |
Model1.h
#import <Foundation/Foundation.h>
@interface Model1 : NSObject {
double accumulator;
double operand;
char operation;
}
-(void) input: (NSNotification *)notification;
-(id) init;
-(void) equal;
@end |
|
Notify versus direct method invocation
There is no single criteria for using notifications but there is always
overhead.
Notify provides at least two advantages over direct method invocation,
explored above:
- Decoupling of components.
- Sending message to an arbitrary number of objects.
Consider a music app that could do any or all of:
- play musical piece
- display artist info
- display musical score
- search for same piece by others
The user could select which of the four they wanted. Each selected could
be added as an observer to be notified on a
change of musical piece.
Obviously, either notification or direct invocation could be used. The
issue is the degree of coupling and generality of the components.