我最终按照his answer 中建议的 TawaNicolas 进行操作,通过使用getDeliveredNoti.... 获取收到的通知,然后检查每个通知的 userInfo 以找到我想要删除的通知。我将可移动通知的标识符存储在一个数组中,并调用removeDelivered...。
这正是他的回答所暗示的,但一开始并没有奏效,我很难找出原因。我仍然不能完全确定我是否已修复它,但我的测试表明它正在工作 - 我的解决方案有点道理。
问题是,在didReceiveRemote.. 函数中,你必须在最后调用completionHandler(.newData)。这是为了通知 NotificationCenter 发生了一些变化。我开始怀疑这个回调是在 可移动通知实际被删除之前调用的。我检查了文档,removeDeliveredNotifications 确实是异步的。这意味着当我这样做时:
UNUserNotificationCenter.current().removeDeliveredNotifications(withIdentifiers: removableIDs)
completionHandler(.newData)
不保证第一个函数在调用第二个函数之前完成。这意味着 completionHandler 告诉我的 NotificationCenter 某些内容已经更新,首先完成,然后通知从系统中删除。 (NotificationCenter 显然不会在该函数之后调用自己的 completionHandler 来更新 UI)。
所有这些可能会或可能不会发生。正如我所经历的那样;当连接到调试器时,removeDeliveredNotifications 函数非常快,以至于它总是在调用completionHandler 之前完成,这意味着在更新系统之前通知已被删除。所以在开发这个时一切看起来都很棒。当我与调试器断开连接时,removeDeliveredNotifications-函数稍微慢了一点,并且由于它是异步的,它在我调用 completionHandler 之后完成 - 导致系统更新得太快。 p>
解决此问题的最佳方法是 Apple 为 removeDeliveredNotifications 提供一个 completionBlock,并在其中调用我们的 completionHandler,但他们没有。
为了解决这个问题,我现在添加了 0.2 秒的固定延迟。它可能低于 0.2,但对于我们正在做的事情来说,它并不重要。
这是我创建的一个类和函数,可以轻松地从任何地方延迟某些东西:
class RuntimeUtils{
class func delay(seconds delay:Double, closure:@escaping ()->()){
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + Double(Int64(delay*Double(NSEC_PER_SEC))) / Double(NSEC_PER_SEC), execute: closure)
}
}
这里我在didReceiveRemoteNotification:AppDelegate中使用它:
UNUserNotificationCenter.current().removeDeliveredNotifications(withIdentifiers: removableIDs)
RuntimeUtils.delay(seconds: 0.2, closure: {
completionHandler(.newData)
})
将这个延迟添加到completionHandler后,它总是在我删除通知后执行,并且似乎每次都有效,无论是否连接了调试器。
这是一个令人作呕的问题,而且修复得很糟糕。