繁体   English   中英

等待异步代码完成Swift

[英]Wait for async code to finish Swift

我一直在从事我的项目之一,在该项目中,我允许用户在所需的时间安排多个通知。 我正在iOS 10中使用新的UserNotifications

为了正确安排所有通知,每个通知都必须具有自己的唯一标识符。 我根据我的数据模型组成了我的:

  1. 我的模特编号
  2. 每次创建新通知时递增的数字
  3. 上面用下划线隔开

因此,例如,如果我必须为ID为3的对象安排15条通知,则其外观应为: 3_1, 3_2, 3_3...3_15

这是我的做法:

@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 ,它使用前一个函数返回的字典来生成适当的标识符。

例如,如果在磁盘上传递了5条通知,而其他10条正在等待ID为3的模型,则它将如下所示:

["3" : 15]

createNotification只是将要在字典中获取值并将其递增1以创建标识符。

真正的问题是:

UNUserNotificationCenter.current().add(takeMedecineRequest, withCompletionHandler: { (error) in
            if let _ = error {
                print("There was an error : \(error)")
            }
        })

这是一个异步任务。 考虑到它不会等待,一旦我回到generateNotifications的循环,由于通知未完成创建,因此checkDeliveredAndPendingNotifications不会返回正确的字典。

考虑上面的示例,如果我必须安排3条通知,我想获得以下信息:

print("identifierDictionary -> \(identifierDictionary)") // ["3":15], ["3":16], ["3":17]
print("unique identifier created -> \(takeMedecineIdentifier") // 3_16, 3_17, 3_18

但是现在我得到:

print("identifierDictionary -> \(identifierDictionary)") // ["3":15], ["3":15], ["3":15]
print("unique identifier created -> \(takeMedecineIdentifier") // 3_16, 3_16, 3_16

因此,如何回到异步循环之前等待异步调用完成?

在此先感谢您的帮助。

如果不需要从标识符“读取”到哪个通知,则可以使用随机字符串作为标识符。

即使像现在一样可以正确地生成唯一的ID,也不应依赖于控制流来正确生成ID。 通常认为这是不良的编码做法,尤其是在依赖(第3个)第三方库或API的情况下。 一种更改可能会破坏它。

您可以按照此处所述生成随机字符串。 使用包含24个字符的字母数字字符串可得到(36 + 36 + 10)^ 24个组合,从而使碰撞的机会微不足道。

您可以使用userinfo词典或某些其他持久性方式将标识符与特定通知相关联。 如果您使用的是CoreData ,则可以将具有唯一标识符的通知对象与medicineRequests关联。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM