사용자가 원하는 시간에 여러 알림을 예약 할 수있게 해주는 프로젝트 중 하나에서 작업하고 있습니다. iOS 10에서 새로운 UserNotifications
을 사용하고 있습니다.비동기 코드 대기 완료 Swift
모든 알림을 올바르게 예약하려면 각 알림에 고유 한 고유 식별자가 있어야합니다. 내 데이터 모델에있어서 내 구성 :
- 내 모델의 ID
- 새로운 통지 위 밑줄로 구분되어 생성 될 때마다 증가하는 숫자
예를 들어 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
을 호출합니다.
["3" : 15]
가 createNotification
단순히 사전에 값을 걸릴 것입니다 : 예를 들어
는 같을 것이다 아이디 3 모델을 기다리고 디스크에 전달 5 알림 및 10 다른 사람이 있다면 식별자를 생성하기 위해 1 씩 증가시킵니다. 그것은 비동기 작업입니다
UNUserNotificationCenter.current().add(takeMedecineRequest, withCompletionHandler: { (error) in
if let _ = error {
print("There was an error : \(error)")
}
})
:와
진짜 문제는 온다. 그것이 지연되지 않는다는 것을 고려하면, generateNotifications
의 루프로 돌아 가면 checkDeliveredAndPendingNotifications
은 알림 작성을 완료하지 않았기 때문에 올바른 사전을 반환하지 않습니다.
print("identifierDictionary -> \(identifierDictionary)") // ["3":15], ["3":16], ["3":17]
print("unique identifier created -> \(takeMedecineIdentifier") // 3_16, 3_17, 3_18
하지만 지금은 내가 갖는 : 나는 3 알림을 예약해야한다면 나는 이런 식으로 뭔가 좀하고 싶습니다 위의 예를 고려
그래서
print("identifierDictionary -> \(identifierDictionary)") // ["3":15], ["3":15], ["3":15]
print("unique identifier created -> \(takeMedecineIdentifier") // 3_16, 3_16, 3_16
을 어떻게 이 비동기 호출이 내 루프로 돌아 가기 전에 완료 될 때까지 기다릴 수 있습니까?
미리 도움을 주셔서 감사합니다.
통지 인 식별자에서 '읽을'수 있어야합니까? 대신 식별자로 [randomized string] (http://stackoverflow.com/a/33860834/4019540)을 사용할 수 있습니다. 가능하다면 올바른 ID 생성을 위해 제어 흐름에 의존해서는 안되며, 하나의 코드 또는 API가 변경되면 모든 것이 손상 될 수 있습니다. – Thomm
@Thomm 예, 불행히도. 식별자를 사용하여 보류 중 및 전달 된 알림 만 제거 할 수 있습니다. 나는이 id를 통보 요청의 userInfo 딕셔너리에 전달하고 식별자에 대한 무작위 화 된 문자열을 생성 할 수 있지만, 두 개의 통보에 당신의 링크를 따라 가면서 동일한 식별자가 없다는 것을 확신 할 수 있습니까? 식별자가 고유하지 않으면 모든 알림을 전달하지 않아 내 앱을 위반하게됩니다. – Croisciento
다른 시드를 사용하는 [arc4random] (https://developer.apple.com/legacy/library/documentation/Darwin/Reference/Man4agesom_uniform.3.html)을 사용하므로 동일한 시퀀스가 생성되지 않습니다. 24 문자의 영숫자 문자열을 사용하면 (36 + 36 + 10)^24 개의 조합이 생겨 충돌을 무시할 수 있습니다. – Thomm