Reputation: 2616
The private AppSupport
framework on iOS has a class called CPDistributedNotificationCenter
which appears to support a subset of the functionality provided by NSDistributedNotificationCenter
on OS X.
I'm attempting to use this class to post notifications from a background daemon such that multiple clients in other processes can receive these notifications and act on them. I realize there are other options, including CPDistributedMessagingCenter
or CFMessagePort
, low level mach ports or even darwin's notify_post
. I'd prefer it if the daemon had no knowledge of the clients however, and I'd like to be able to pass data along with the notification, and notify_post
does not allow this.
Currently, this is what I am doing in the daemon:
CPDistributedNotificationCenter* center;
center = [CPDistributedNotificationCenter centerNamed:@"com.yfrancis.notiftest"];
[center runServer];
[center postNotificationName:@"hello"];
And in the client:
CPDistributedNotificationCenter* center;
center = [CPDistributedNotificationCenter centerNamed:@"com.yfrancis.notiftest"];
[center startDeliveringNotificationsToMainThread];
NSNotificationCenter* nc = [NSNotificationCenter defaultCenter];
[nc addObserver:[Listener new]
selector:@selector(gotNotification:)
name:@"hello"
object:nil];
where Listener
is a simple class that implements a single method gotNotification:
Unfortunately, the client never receives the 'hello' notification. If I replace the name
argument in the addObserver
call with nil
I can see every notification delivered to the client's notification center, but 'hello' is not one of them.
I got the inspiration for my code by looking at a disassembly of SpringBoard
and CPDistributedNotificationCenter
. Notifications appear to be delivered via CPDistributedNotificationCenter
's deliverNotification:userInfo:
which acts as a shim for NSNotificationCenter
's postNotificationName:object:userInfo:
.
What am I missing here?
Upvotes: 4
Views: 1685
Reputation: 2616
Figured it out. Your daemon has to wait for a notification indicating that a client has started listening, before sending out your notification. There is no backlog, even if the daemon server runs before the client, there is a registration delay. You can't simply start your server and immediately post notifications to listeners. The following works for me:
In the server init:
self.center = [CPDistributedNotificationCenter centerNamed:@"com.yfrancis.notiftest"];
[self.center runServer];
// requires a runloop
NSNotificationCenter* nc = [NSNotificationCenter defaultCenter];
[nc addObserver:self
selector:@selector(clientEvent:)
name:@"CPDistributedNotificationCenterClientDidStartListeningNotification"
object:self.center];
And make sure to implement the following method in the server:
- (void)clientEvent:(NSNotification*)notification
{
// you can now send notifications to the client that caused this event
// and any other clients that were registered previously
[self.center postNotificationName:@"hello!"];
{
I've documented this API on the iPhoneDevWiki
Upvotes: 5