It's worth to learn new languages. You can always learn something new, get more experienced, and see things from different angle.
Today I will show and compare how notifications are implemented in Java and Objective-C.
Java Observable/Observer
Let's say we have a
Downloader which downloads files from the Internet. Files usually take some time to download, so we download them in a separate thread. Upon completion we would like to notify everyone who was interested that download has finished and file is ready:
public class Downloader extends Observable implements Runnable {
private URL url;
public Downloader(String url) throws MalformedURLException {
this.url = new URL(url);
new Thread(this).start();
}
public void run() {
// let's say I'm downloading the contents of url here
// sleep for 1 second :)
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
}
// I downloaded it
byte[] downloadedFileOrSomethingElse = {1,2,3};
// important!
// mark Observable instance as changed!
// otherwise notification won't be propagated - see impl for more details
setChanged();
notifyObservers(downloadedFileOrSomethingElse);
}
}
Let's say we have a view class which is interested in receiving notifications from the
Downloader, the implementation might look like this:
public class MyView implements Observer {
@Override
public void update(Observable o, Object arg) {
System.out.printf("Got observable ==> %s argument ==> %s", o, arg);
// do something to update view of what ever
}
}
To register
MyView for notifications I wrote:
MyView view = new MyView();
Downloader downloader = new Downloader("http://www.kernel.org/download-linux-kernel.for.example");
// upon completion of download view will be notified so that it can update its contents properly
downloader.addObserver(view);
// give test some time
Thread.sleep(3000);
Advantages, drawbacks?
This is purely OO way of using notifications. Observable must hold references to all observers, which must adhere to some kind of interface.
Objective-C Notifications
Using iPhone Objective-C notifications mechanism observable and observers don't have to know anything about themselves. Observable posts notification to internal queue. Observer subscribes to it and provides information on what method to call when notification arrives.
Assume in
ViewController you have the following code:
// 1. create downloader instance
Downloader *downloader = [Downloader new];
// 2. register current view controller for notifications called "DocumentDownloaded" posted by downloader object (last two parameters are optional)
// upon recieving notification invoke showDocumentView method
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(showDocumentView:) name: @"DocumentDownloaded" object: downloader];
// 3. create NSURLConnection instance (on the iPhone it automatically starts in the background)
// as a delegate pass downloader object
NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest: request delegate: downloader];
Then in
downloader delegate, at the end of
connectionDidFinishLoading callback method, post notification:
-(void)connectionDidFinishLoading:(NSURLConnection *)connection {
[connection release];
self.contents = [[NSString alloc] initWithBytes:[webData mutableBytes] length:[webData length] encoding:NSUTF8StringEncoding];
[webData release];
NSNotification *notification = [NSNotification notificationWithName: @"DocumentDownloaded" object: self];
[[NSNotificationCenter defaultCenter] postNotification: notification];
}
Finally the
showDocumentView method of our
ViewCOntroller might look something like this:
-(void) showDocumentView: (NSNotification *)notification {
Downloader *downloader = (Downloader*) [notification object];
NSString* data = downloader.contents;
// do something with data
}
Summary
I like Objective-C approach more. It's something very different from Java and I like it :) I like it because it's 100% loosely coupled. Observable and observers don't have to know anything about themselves.
Of course you can implement this approach in Java as well. You can create static queues, and replace dynamic Objective-C selectors with Java Reflections (or Groovy callbacks)... But that's a different story.
Cheers,
Łukasz