Я работаю над одним из своих проектов, где я позволяю пользователям планировать несколько уведомлений в нужное время. Я использую новый UserNotifications
в iOS 10.
Для правильного планирования всех уведомлений каждое уведомление должно иметь собственный уникальный идентификатор. Я составил свой в соответствии с моими моделями данных:
- Идентификатор моей модели
- Число, которое увеличивается каждый раз, когда создается новое уведомление.
- Вышеупомянутое разделено подчеркиванием
Так, например, если бы мне нужно было запланировать 15 уведомлений для объекта с идентификатором 3, это выглядело бы так: 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 других ожидают модель с идентификатором 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
Итак, как я могу дождаться завершения этого асинхронного вызова, прежде чем вернуться к моему циклу?
Заранее спасибо за помощь.