The basic insight, and it is a pretty trivial one, is that a notification is just a broadcast message. So when we have real messaging, which we do, notifications consist of sending a message to a dynamically defined set of receivers.
How can we send a message, for example -modelDidChange:
to a set of receivers? With HOM that's also trivial:
[[receivers do] modelDidChange:aPath];
So how do we define the set of receivers? Well, the collection is defined as all the objects listening to a particular notification, in this case this notification is the message. So instead of
do
, we
need a notify:
HOM that collects all the receivers registered for that message:
[[center notifyListenersOf:@selector(modelDidChange:)] modelDidChange:aPath];
But of course this is redundant, we already have the
modelDidChange:
message in the argument
message of the HOM. So we can remove the argument from the notify
HOM:
[[center notify] modelDidChange:aPath];
A trivial notification center now is just a dictionary of arrays of receivers, with the keys of the dictionary being the message names. With that dictionary called
receiversByNotificationName
,
the notify
HOM would look as follows:
DEFINE_HOM(notify, void)
{
NSString *key = NSStringFromSelector([invocation selector]);
NSArray *receivers = self.receiversByNotificationName[key];
[[invocation do] invokeWithTarget:[receivers each]];
}
Of course, you can also integrate with
NSNotificationCenter
by using the converted message
name as the NSNotification
name.You would then register for the notification with the following code:
-(void)registerNotificationMessage:(SEL)aMessage
{
[[NSNotificationCenter defaultCenter] addObserver:self selector:aMessage name:NSStringFromSelector(aMessage) object:nil];
}
The HOM code is a little more involved, I'll leave that as an exercise for the reader.
So, by taking messaging seriously, we can get elegant notifications in even less code than Notification Protocols. The difference is that Notification Protocols actually let you declare adoption of a notification statically in your class's interface, and have that declaration be meaningful.
@interface MyGreatView : NSView <ModelDidChangeNotification>
Another aspect is that while HOM is almost certainly too much for poor old Swift to handle, it should be capable of dealing with Notification Protocols. It is!