UNUserNotificationCenter.current().removeDeliveredNotifications() is hanging

An app is hanging randomly on app launch, after looking into it, it appears it's hanging on a call to UNUserNotificationCenter.current() calls. I say this because there's logging and the sometimes the last line logged is prior to a call to UNUserNotificationCenter()

I have a hang log (.ips file) rom the iPhone and at the bottom it says this. I presume blockingThreadInfo is talking about the thread being blocked, and it identifies the topBlockingProcess as user notifications.

  "blockingThreadInfo" : {
    "topBlockingProcess" : "usernotificationsd",

The following is the code, why would this code cause a hang? The problem occurs when there's lots of notifications that have been posted i.e. something like 100.

[[NSNotificationCenter defaultCenter] addObserver:self
                     selector:@selector(appBecameActive)
                       name: UIApplicationDidBecomeActiveNotification
                       object:nil];


@objc func appBecameActive() {
  method1()
  method2()
}


@objc func method1() {
  UNUserNotificationCenter.current().getDeliveredNotifications { notifications in
    if SettingsManager.isProductionFinalBuild() == false {
      // Log notification center contents
      for notification in notifications {
        let title = notification.request.content.title
        let targetId = notification.request.content.targetContentIdentifier
        let threadId = notification.request.content.threadIdentifier
        let categoryIdentifer = notification.request.content.categoryIdentifier
        let identifier = notification.request.identifier
        let info = notification.request.content.userInfo
        Logger.trace("Previously delivered notification: title: \(title) identifier: \(identifier) threadId: \(threadId) category: \(categoryIdentifer) target id: \(String(describing: targetId)) userInfo: \(info)")
      }
      
      let matchchingNotifications = notifications.filter({ $0.request.identifier == kMdnAccountNotFoundNotificationIdentifier })
      UNUserNotificationCenter.current().removeDeliveredNotifications(withIdentifiers: [kMdnAccountNotFoundNotificationIdentifier])
    }
  }
  
  
  func method2() {
	UNUserNotificationCenter.current().removePendingNotificationRequests(withIdentifiers: [Constants.kWhatsNewNotificationIdentifier])
      
      UNUserNotificationCenter.current().removeDeliveredNotifications(withIdentifiers: [Constants.kWhatsNewNotificationIdentifier])
 }

Replies

You might need to batch the list of messages and do the remove in blocks that don't take so long on a serial thread. The tasks could dispatch the remove action to an appropriate thread if needed. I did that for a potentially long running import process using the Combine framework.