在iOS 10中安排和处理本地通知

时间:2016-10-11 13:02:47

标签: ios objective-c swift notifications unusernotificationcenter

我一直致力于我的一个项目,我允许用户在所需的时间安排多个通知。

iOS 10让我们能够使用DateComponents作为我们通知的开火日期,但我有点迷失了我应该如何安排和处理多个通知。

每个通知都需要自己的请求,然后需要自己的标识符,否则您无法创建多个通知。

我认为我必须使用标识符来安排和处理通知,但现在我的代码太乱了,我一直在认真地问自己,如果没有更简单的方法来做这件事

根据我的数据模型,通知唯一标识符由以下内容组成:

  1. 我的模特的身份
  2. 每次创建新通知时递增的数字
  3. 上面用下划线
  4. 分隔

    例如,如果我必须为ID为3的对象安排10个通知,它将如下所示:3_1, 3_2, 3_3...

    每次收到通知时,我都会通过收到的通知循环更新我的用户界面。并且当用户希望删除针对特定模型的所接收的通知时,我通过检查以相同ID开始的标识符来遍历所接收的通知的唯一标识符。

    我真的不知道如何设法做到这一点,因为根据文档,删除已发送通知的唯一方法是使用标识符:UNUserNotificationCenter.current().removeDeliveredNotifications(withIdentifiers:)

    问题是,它创造了各种各样的问题,虽然我可以很容易地纠正它们,但它看起来非常h​​acky。我并不为我所做的事感到骄傲,我正在寻找更聪明的方法来解决这个问题。我故意没有发布任何代码,因为这不是问题。这种方法是真正的问题。

    我在这里问,因为UserNotifications框架很新,而且我还没有能够找到关于这个主题的资源。

    有什么想法吗?提前谢谢。

    编辑:这里有一些代码。

    @available(iOS 10.0, *)
        func checkDeliveredAndPendingNotifications(completionHandler: @escaping (_ identifierDictionary: Dictionary<String, Int>) -> ()) {
    
            var identifierDictionary:[String: Int] = [:]
            UNUserNotificationCenter.current().getDeliveredNotifications { (notifications) in
    
                for notification in notifications {
                    let identifierArraySplit = notification.request.identifier.components(separatedBy: "_")
                    if identifierDictionary[identifierArraySplit[0]] == nil || identifierDictionary[identifierArraySplit[0]]! < Int(identifierArraySplit[1])!  {
                        identifierDictionary[identifierArraySplit[0]] = Int(identifierArraySplit[1])
                    }
                }
    
                UNUserNotificationCenter.current().getPendingNotificationRequests(completionHandler: { (requests) in
                    for request in requests {
                        let identifierArraySplit = request.identifier.components(separatedBy: "_")
                        if identifierDictionary[identifierArraySplit[0]] == nil || Int(identifierArraySplit[1])! > identifierDictionary[identifierArraySplit[0]]!  {
                            identifierDictionary[identifierArraySplit[0]] = Int(identifierArraySplit[1])
                        }
                    }
                    completionHandler(identifierDictionary)
                })
            }
        }
    
    
    @available(iOS 10.0, *) 
        func generateNotifications() {
            for medecine in medecines {
                self.checkDeliveredAndPendingNotifications(completionHandler: { (identifierDictionary) in
                    DispatchQueue.main.async {
                        self.createNotification(medecineName: medecine.name, medecineId: medecine.id, identifierDictionary: identifierDictionary)
                        }                    
                })
            }
        }
    
    
    @available(iOS 10.0, *)
        func createNotification(medecineName: String, medecineId: Int identifierDictionary: Dictionary<String, Int>) {
    
            let takeMedecineAction = UNNotificationAction(identifier: "TAKE", title: "Take your medecine", options: [.destructive])
            let category = UNNotificationCategory(identifier: "message", actions: [takeMedecineAction], intentIdentifiers:[], options: [])
            UNUserNotificationCenter.current().setNotificationCategories([category])
    
            let takeMedecineContent = UNMutableNotificationContent()
            takeMedecineContent.userInfo = ["id": medecineId]
            takeMedecineContent.categoryIdentifier = "message"
            takeMedecineContent.title = medecineName
            takeMedecineContent.body = "It's time for your medecine"
            takeMedecineContent.badge = 1
            takeMedecineContent.sound = UNNotificationSound.default()
    
            let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 60, repeats: false)
    
            var takeMedecineIdentifier = ""
            for identifier in identifierDictionary {
                if Int(identifier.key) == medecineId {
                    let nextIdentifierValue = identifier.value + 1
                    takeMedecineIdentifier = String(medecineId) + "_" + String(nextIdentifierValue)
                }
            }
            let takeMedecineRequest = UNNotificationRequest(identifier: takeMedecineIdentifier, content: takeMedecineContent, trigger: trigger)
    
            UNUserNotificationCenter.current().add(takeMedecineRequest, withCompletionHandler: { (error) in
                if let _ = error {
                    print("There was an error : \(error)")
                }
            })
        }
    

    checkDeliveredAndPendingNotifications方法中,我遍历所有待处理和已发送的通知,因此稍后我可以创建一个不存在的标识符。我还没有找到另一种方法来为每个通知生成唯一标识符。

    由于大多数工作是在另一个异步队列上完成的,所以我在完成工作后也创建了一个完成处理程序。然后我在主线程上调用createNotification方法(因为我使用了Realm,我也有义务这样做),这应该会创建一个通知。

    这里的问题是func add(UNNotificationRequest, withCompletionHandler: (Error?) -> Void)? = nil)方法,它也是异步工作。因此,当我在generateNotifications中回到我的循环时,checkDeliveredAndPendingNotifications会返回不正确的数据。那不是不正确的,只是通知还没有创建......

    我是一个带线程的总菜鸟,我一直坚持这种操作,我不知道该往哪里去。我不确定我是否以正确的方式解决问题。

1 个答案:

答案 0 :(得分:0)

您可以根据需要获取所有通知并设置/删除。看看Objc c和swift的接受答案。

How to schedule a local notification in iOS 10 (objective-c)