Yes, another Mac post. Is this nuts or what?
Anyway, I’ve been doing more work with Obj-C and the Cocoa APIs. Specifically I’ve been figuring out how to use NSAlert (the equivalent of MessageBox in WinForms) and also how to work with their networking APIs to do things like GET and POST. While these things may not seem to be related, what they do have in common is the communication between objects.
Now, for the .NET audience, we have delegates which is as the equivalent of strongly typed function pointers. Most of the time delegates are used to implement events and then we have the basic pub/sub pattern of event notification.
Well, first off, Obj-C doesn’t really have functions so to speak because it is a message based language, therefore there is no such thing as a function pointer. So Cocoa uses a few common patterns to enable communication between objects:
This works by handing someone an instance of an object, referred to as the delegate, and that object is expected to implement an interface. Now… there’s not really interfaces in Obj-C either (not in the strongly typed sense that we think of them in .NET). There’s just this concept of a loosely defined contract of messages which you can selectively “opt-in” to implementing. They refer to this as an “informal protocol”. So basically if you only want to handle one message in this contract you just implement that message signature (down to the exact message name) on your delegate and it will be called. Any other messages in that informal protocol that don’t have implementations will essentially be no-op’d by the caller.
There’s really no direct equivalent of this pattern in use in .NET to be honest. It’s essentially leveraging the power of messaging to do it’s work. I don’t exactly like the approach, but I get it.
The only negative to this pattern is that you may only have one delegate listening to you this way. If you wanted multiple people to be notified you’d have to use something called “notifications” that is detailed below. One aspect that they tout being especially great about this approach over notifications is that you can return values that indicate what the sender of the message is supposed to do. The same is true in .NET technically since you can’t return a value from a multi-cast delegate (aka event). However there are patterns that use the event arguments to communicate state. .NET has CancelEventArgs for this type of thing and the same pattern is used in DHTML (see stopPropagation/preventDefault) and WPF (see RoutedEventArgs::Handled) to indicate whether the logical event should continue.
Probably the most familiar pattern to a .NET person. Basically think of the scenario where you have a Button and you want to know when that button’s clicked. We all know how to do that in .NET right? Just implement a method that matches a particular signature, defined by some event handler delegate, and hook it up to the instance’s event.
What happens in Cocoa/Obj-C is that you hand someone an instance of an object, referred to as the target, and a “selector” which indicates exactly what message you want sent back to object when the action occurs. The message just needs to take the same parameters as the defining action message signature, but can be named something different. This is almost exactly the same as using delegates to listen to events in .NET, but it’s a little different because, unlike delegates in .NET, you must specify these two things separately to the object you want to notify you. Also, the message contract is again little more loosely defined.
While this pattern makes certain things very simple in the Cocoa world, there’s two pitfalls with this approach that I see:
- No way to have more than one listener in this pattern.
- You can basically have only one action in this pattern, which means for a button you can have it fire it’s “click” action in this way, but all the other stuff like handling key presses and mouse overs requires you to go back to using the delegate pattern anyway.
Notifications are basically the closest thing to .NET events from a conceptual point of view, but are very different from an implementation point of view. They’re similar because they allow multiple subscribers and the signature of the method is void since the result of each of the subscribers is meaningless. That’s where the similarities end though.
Notifications are implemented by describing a message whose signature takes a single parameter of type NSNotification.