NSUserNotificationCenter and caching

I've been observing an annoying phenomenom with NSUserNotificationCenter/NSUserNotification.


I have 2 processes:

- procD: a launchd daemon launched at startup

- procA: a launchd agent launched at login


. procA can also be launched by procD using a watch path.


. procD communicates through XPC with procA using an anonymousListener endpoint provided by procA.


. procD can send a message (MSG) to procA through XPC. The message in procA delivers a NSUserNotification.


What I've been observing:


Case that works:


procD is running.

procA is running and has been launched automatically after login.


1. procD sends MSG to procA. procA receives the message, uses the NSUserNotification API to deliver a user notification: it works fine.


Step 1 can be repeated again and again and it works fine in every single case.


Case that does not work:


procD is running.

procA is running and has been launched automatically after login.


1. procA is killed (via Activity Monitor for instance).

2. procD triggers the launch of procA using the watch path => procA is launched.

3. procD sends MSG to procA. procA receives the message, uses the NSUserNotification API to deliver a user notification


=> the user notification does not appear. It i reported as delivered to the NSUserNotificationCenter delegate. Uh?!


4. procD sends MSG to procA. procA receives the message, uses the NSUserNotification API to deliver a user notification


=> the notification does appear.



It's as if delivering a user notification following a kill of the process is not working. I have added a NSBeep() before delivering the notification and it's played. So the issue really is with the user notification code and not the messaging code.



Workaround that I've found so far:


I call [[NSUserNotificationCenter defaultUserNotificationCenter] removeAllDeliveredNotifications] in the + (void)initialize method of the class I use to call the NSUserNotification API and deliver the notifications.


Doing this enables the first user notification to be displayed as it should.


Question:


Could it be that there is a bug in the NSUserNotificationCenter/NSUserNotification API/server where some cached data remains after a process has been killed?


I've read that these APIs are deprecated but they are the only ones that work on macOS < 10.14 which is still supported here.



macOS 10.14.6 / Objective-C code

Replies

Could you detail the difference between 3 and 4 ? Or is just 4 a repeat of 3 and this repeat works ?

1. procA is killed (via Activity Monitor for instance).

2. procD triggers the launch of procA using the watch path => procA is launched.

3. procD sends MSG to procA. procA receives the message, uses the NSUserNotification API to deliver a user notification

=> the user notification does not appear. It i reported as delivered to the NSUserNotificationCenter delegate. Uh?!

4. procD sends MSG to procA. procA receives the message, uses the NSUserNotification API to deliver a user notification

=> the notification does appear.


Could you show the corresponding code for 3 (and thus, 4).

Have you tried the UNUserNotification class instead? It is available on 10.14 too.


Could there be a bug where some cached data remains after a process has been killed? Of course. Bug or not, it exhibits the behaviour that it has and you aren't going to get that changed for 10.14 or even 10.15 at this point. That's the way it works.


Here are some things you could try:

1) If you have to restart procA, since a "prime the pump" notification to get things going again. If it isn't displayed, all the better.

2) Schedule the notification for a couple of seconds in the future.

3) Just wait a couple of seconds before sending the notification.

4) Use your workaround. If you have a workaround, what's the big deal? You want an API without bugs? You're on the wrong platform!

Step 4 is just repeating step 3.


So if you send the same message 2 times, the first time, the notification is not displayed. The second time, the notification is displayed.

Delaying either in the daemon or in the agent does not solve the issue.

Less than a cache, it looks like a connection was not established until you try (and fail) to send the first one.

As I'm observing other issues with notifications, I'm starting to wonder whether I'm not misinterpreted the documentation for the identifier property of the NSUserNotification object.


According to the documentation:


@property(copy) NSString *identifier;


"The identifier is unique to a notification. A notification delivered with the same identifier as an existing notification replaces the existing notification rather than causing the display of a new notification."



Note: The application/agent is set to display notifications as banners (by default).


The way I understand it is, in the context of banners:


When a notification with a unique identifier is delivered:


- if a notification with the same unique identifier has been delivered and its banner is still visible, the visible banner will be replaced with the new one.

- if a notification with the same unique identifier has been delivered and its banner is no more visible, a new banner will pop up.


What I'm observing:


- if a notification with the same unique identifier has been delivered and its banner is no more visible, no new banner pops up.


And it looks like I'm facing the same case as these persons:


https://stackoverflow.com/questions/38465355/objectivec-how-to-use-nsusernotification-identifier-property