3

I have some code in my Mac app that performs a long-running export operation. At the end of the export, it creates a user notification to let the user know it's finished:

- (NSUserNotification*)deliverNotificationWithSound:(NSString*)sound title:(NSString*)title messageFormat:(NSString*)message {
    NSUserNotification * note = [NSUserNotification new];

    note.soundName = sound;
    note.title = title;
    note.informativeText = [NSString stringWithFormat:message, NSRunningApplication.currentApplication.localizedName, self.document.displayName];
    note.userInfo = @{ @"documentFileURL": self.document.fileURL.absoluteString };

    [NSUserNotificationCenter.defaultUserNotificationCenter deliverNotification:note];
    return note;
}

It then puts a sheet up with details about the export (warnings encountered, a handy "Reveal" button, etc.). When they dismiss the sheet, I want to remove the notification, like so:

[NSUserNotificationCenter.defaultUserNotificationCenter removeDeliveredNotification:note];

However, this doesn't actually remove the notification from Notification Center. I've set a breakpoint; the -removeDeliveredNotification: line is run, and note is not nil. What gives?

Charles
  • 50,943
  • 13
  • 104
  • 142
Becca Royal-Gordon
  • 17,541
  • 7
  • 56
  • 91
  • 1
    Are you sure the notification has been delivered (check the `presented` property on the notification and the `deliveredNotifications` property on the notification center) Quoth the docs for `-removeDeliveredNotification:`: "If the user notification is not in deliveredNotifications, nothing happens." Also, if the issue is that the display bubble in the top right corner of the screen is not automatically closed, see http://stackoverflow.com/questions/12113300/nsusernotificationcenter-dismiss-notification – jatoben Feb 27 '13 at 00:31
  • `-isPresented` returns NO, and it looks like `-[NSUserNotificationCenter deliveredNotifications]` actually contains a separate instance of `NSUserNotification` that's identical to mine. Seriously, Apple? I guess I'll have to put something in the userInfo to link the two instances... – Becca Royal-Gordon Feb 27 '13 at 02:42
  • @jatoben I've now got a fixed version. If you want to post an answer, I'll accept it and edit in my corrected code. – Becca Royal-Gordon Feb 27 '13 at 03:35

2 Answers2

1

The notification you are attempting to be removed must be in the deliveredNotifications array. Quote the docs for -removeDeliveredNotification:

If the user notification is not in deliveredNotifications, nothing happens.

Your notification may be copied when you call -deliverNotification:, so keeping a reference to that instance and attempting to remove later it may fail. Instead, stash something in the notification's userInfo property so you can identify it, and scan through the deliveredNotifications array to find the notification you want to remove.


Added by Brent

Here's the corrected version of the method in my question. I'm using the original notification's pointer value, casted to an integer, to identify the copy; this isn't foolproof, but it's probably good enough.

- (NSUserNotification*)deliverNotificationWithSound:(NSString*)sound title:(NSString*)title messageFormat:(NSString*)message {
    NSUserNotification * note = [NSUserNotification new];

    note.soundName = sound;
    note.title = title;
    note.informativeText = [NSString stringWithFormat:message, NSRunningApplication.currentApplication.localizedName, self.document.displayName];
    note.userInfo = @{ @"documentFileURL": self.document.fileURL.absoluteString, @"originalPointer": @((NSUInteger)note) };

    [NSUserNotificationCenter.defaultUserNotificationCenter deliverNotification:note];

    // NSUserNotificationCenter actually delivers a copy of the notification, not the original.
    // If we want to remove the notification later, we'll need that copy.
    for(NSUserNotification * deliveredNote in NSUserNotificationCenter.defaultUserNotificationCenter.deliveredNotifications) {
        if([deliveredNote.userInfo[@"originalPointer"] isEqualToNumber:note.userInfo[@"originalPointer"]]) {
            return deliveredNote;
        }
    }

    return nil;
}
Becca Royal-Gordon
  • 17,541
  • 7
  • 56
  • 91
jatoben
  • 3,079
  • 15
  • 12
0

Thanks for the great question.

It seems like Apple was fixed issue because it will work for me by using the single line of code.

UNUserNotificationCenter.current().removeDeliveredNotifications(withIdentifiers: aryIdentifier)

I have tried 5-6 hours in the simulator to clear local notification but no luck. When I will run code in the actual device it will like the charm.

Happy coding.

Hitesh Surani
  • 12,733
  • 6
  • 54
  • 65