The need for loosely coupled objects is important for all object oriented programming languages.
On Flex projects, this was largely achieved by the EventDispatcher and Event classes. Nearly every class either inherited from EventDispatcher or had an EventDispatcher and implemented the IEventDispatcher interface.
So, to have a button run your custom code when clicked, you would do this
loginButton.addEventListener(MouseEvent.CLICK, loginButton_clickHandler, false, 0, false);
This would basically log a callback with the loginButton instance. When the button was clicked, it would call its own function
dispatchEvent(new MouseEvent(MouseEvent.CLICK))
which would lookup the list of callbacks registered on itself for the string “click” (MouseEvent.CLICK). It would then execute the callback, passing it a MouseEvent object as an argument. The MouseEvent would have a target property (of type Object) that pointed to the loginButton.
The loginButton instance had a strong reference to the object with the callback (unless the useWeakReference argument to addEventListener was set). But it was loosely-coupled because the loginButton did not know the specific class of that object. It just knew it was of type Object and implemented a method named loginButton_clickHandler which the loginButton should call when the user clicked it.
And so this approach was used throughout Flex projects. Your own custom classes would dispatch custom events using your subclass of Event. You subclass of Event could contain lots of info you needed to pass to another object.
The event model is more complex that basic callbacks because it allows for event bubbling, event phases, event canceling, etc. It also creates a new Event object for all communications, which if you had thousands of objects, might cause a performance issue. But it was a nice system and I enjoyed using it.
There were also a couple of classes that used delegation for callbacks. SharedObject, LocalConnection, NetConnection, and NetStream all had a property named client.
From the documentation for NetStream.client
client:Object
Specifies the object on which callback methods are invoked to handle streaming or F4V/FLV file data. The default object is this, the NetStream object being created. If you set the client property to another object, callback methods are invoked on that other object. The NetStream.client object can call the following functions and receive an associated data object: onCuePoint(), onImageData(), onMetaData(), onPlayStatus(), onSeekPoint(), onTextData(), and onXMPData().
So you would create an instance of NetStream and then set its client property to an object that would have implemented some methods with predefined names such as onCuePoint(). The client property would often be set to the same object that owned the NetStream instance.
A third way that callbacks were sometimes handled in Flex was through the use of anonymous functions. I could not find an asynchronous example in the Adobe provided classes, but here is a synchronous example using the forEach method of the Vector class:
var vector:Vector.<String> = new Vector.<String>();
vector[0] = "0.99";
vector[1] = "1.99";
vector[2] = "2.99";
var callbackFunction:Function = function(item:String, index:int, vector:Vector.<String>):void {
trace("$" + item);
};
vector.forEach(callbackFunction);
Callbacks in iOS
In iOS, there are four main approaches to callbacks:
- Target-action
- Delegation
- Notifications
- Blocks
Target-action
This approach is used a lot and is likely the first you will encounter. When you wire up a UIControl, such as a UIButton, from a NIB you specify an object (the target) that has a callback method (the action).

You can also do this in code.
- (void)viewDidLoad
{
[super viewDidLoad];
[self.loginButton addTarget:self
action:@selector(buttonPress2:)
forControlEvents:UIControlEventTouchUpInside];
}
- (IBAction)buttonPress:(id)sender
{
NSLog(@"button press");
}
- (void)buttonPress2:(id)sender
{
NSLog(@"button press too!");
}
With target-action you do not get compile-time checking to ensure there exists a method that will correspond to the action parameter. Typing in the wrong selector is a common mistake that generates a run-time error.
Delegation
Delegation is where you give one object a reference to second object which implements methods with predefined names. The names of the callback methods are specified by a Protocol.
Protocols are similar to Interfaces in Flex. The main difference being that methods in protocols can be marked as optional.
Two protocols you will use a lot are the UITableViewDataSource and UITableViewDelegate protocols. A UITableView needs customization and rather than subclass it, you use callbacks in another object that conforms to the protocol. Typically this object is your custom subclass of UITableViewController (or UIViewController). UITableViewController is itself a subclass of UIViewController and it does some of the setup work for you. For this example, I’ll just subclass UIViewController.
#import <UIKit/UIKit.h> @interface ViewController : UIViewController @end
#import "ViewController.h"
@interface ViewController () <UITableViewDataSource, UITableViewDelegate>
@property (nonatomic, strong) UITableView *tableView;
@end
@implementation ViewController
- (void)loadView
{
// Your custom implementation of this method should not call super.
self.tableView = [[UITableView alloc] init];
self.tableView.dataSource = self;
self.tableView.delegate = self;
self.view = self.tableView;
}
#pragma mark - UITableViewDataSource
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return 3;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = @"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (!cell)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
switch (indexPath.row)
{
case 0:
cell.textLabel.text = @"$0.99";
break;
case 1:
cell.textLabel.text = @"$1.99";
break;
case 2:
cell.textLabel.text = @"$2.99";
break;
default:
cell.textLabel.text = @"";
break;
}
return cell;
}
#pragma mark - UITableViewDelegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSLog(@"User selected row %d", indexPath.row);
}
@end
The UITableView will call tableView:numberOfRowsInSection: and our UIViewController subclass returns 3.
The UITableView will call tableView:cellForRowAtIndexPath: and our UIViewController subclass either instantiates or recycles an existing UITableViewCell.
(As a side note, UITableViewCell is handled similar to how Flex’s DataGrid handles its ItemRenderer. They get recycled as they move offscreen rather than a new one being instantiated every time.)

And when the user taps a row, the UITableView will call the tableView:didSelectRowAtIndexPath: method.
The important thing here is that UITableView does not know the specific class type (i.e. your custom subclass of UIViewController) that implements the methods it will call. UITableView just knows that its delegate and datasource conform to the UITableViewDataSource and UITableViewDelegate protocols. That is loose coupling.
When you use delegation, you get compile-time checking that the required methods are implemented.
Notifications
Notification in iOS is very similar to using a central EventDispatcher in Flex. There are at least 3 objects involved:
- A NotificationCenter object
- The object that posts the notification to the NotificationCenter
- The object(s) that receives the notification from the NotificationCenter
To keep this example super simple, I am making the object that posts the notification also the object that is observing. You would not do this in practice.
- (void)viewDidLoad
{
// Register the observer
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(loginDidSucceedNotificationHandler:) name:@"LoginDidSucceedNotification" object:nil];
// Post the notification
NSNotification *notification = [NSNotification notificationWithName:@"LoginDidSucceedNotification" object:self userInfo:@{ @"username" : @"Jamie" }];
[[NSNotificationCenter defaultCenter] postNotification:notification];
// Show that the postNotification: method is synchronous
NSLog(@"Exiting viewDidLoad");
}
- (void)loginDidSucceedNotificationHandler:(NSNotification *)notification
{
NSLog(@"User %@ was successfully logged in.", notification.userInfo[@"username"]);
}
- (void)dealloc
{
// NSNotificationCenter holds a strong reference to its observers, so always unregister in dealloc method
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
As was the case with target-action, using notifications does not give you compile-time checking to ensure there exists a method that will correspond to the selector parameter. Typing in the wrong selector is a common mistake that generates a run-time error.
Unlike in Flex where you would subclass Event to contain your strongly-typed custom data (such as LoginEvent.user) you do not subclass NSNotification. Instead you populate a NSDictionary with key-value pairs and set it as the NSNotification.userInfo property.
So if you are coming from Flex to iOS, why not just use NSNotificationCenter for the majority of your object communications like you used EventDispatcher? Well, apparently there are performance considerations for mobile devices. Adobe said as much in their Optimizing Performance for the Flash Platform guide.
The ActionScript 3.0 event model is based on the concept of object dispatching. The event model is object-oriented and optimized for code reuse. The
dispatchEvent() method loops through the list of listeners and calls the event handler method on each registered object. However, one of the drawbacks of the event model is that you are likely to create many objects over the lifetime of your application.Object creation is probably not the issue on iOS that it was with Flash since the Objective-C runtime does not use a garbage collector. However the time it takes to loop through the list of observing objects can start to add up if there are several hundred and you are posting notifications very frequently.
Another thing to keep in mind is, like EventDispatcher.dispatchEvent() in Flex, the NSNotificationCenter postNotification: method is synchronous. It immediately results in the observing object’s callback methods being called (though the order of the objects receiving the notification is not guaranteed).
Blocks
Blocks in iOS are like anonymous functions in Flex.
NSArray *array = @[ @"0.99", @"1.99", @"2.99" ];
[array enumerateObjectsUsingBlock:^(id object, NSUInteger index, BOOL *stop) {
NSLog(@"%@", [@"$" stringByAppendingString:object]);
}];
Like I mentioned above, I could not find an example in Flex of an anonymous function being used for asynchronous operations. But in iOS, block are commonly used for that purpose, and they are referred to as “completion blocks.”
Here is an example that utilizes the block-based animation methods of UIView.
- (void)viewDidLoad
{
UIView *blueSquare = [[UIView alloc] initWithFrame:CGRectMake(10, 10, 100, 100)];
blueSquare.backgroundColor = [UIColor blueColor];
[self.view addSubview:blueSquare];
[UIView animateWithDuration:2.0
animations:^{blueSquare.frame = CGRectMake(210, 10, 100, 100);}
completion:^(BOOL finished) { NSLog(@"Animation complete"); }];
NSLog(@"Exiting viewDidLoad");
}

“Exiting viewDidLoad” get logged first, then the animation occurs over 2 seconds, and finally “Animation complete” gets logged.
The “one more thing” to callbacks in iOS
In addition to target-action, delegation, notifications, and blocks, there is one other approach where objects can be notified when a property of another object changes. It is called Key-Value Observing (often abbreviated KVO).
I’ll save that for another “From Flex to iOS” post however, where I can also talk about the [Bindable] metadata tag that I often used in Flex. Until then, you can read all about it in the iOS documentation.







Curious Find is the website of Jamie McDaniel, a freelance iOS developer located in Lexington, Kentucky.