私は、ユーザーが希望する時間に複数の通知をスケジュールできるようにするプロジェクトの 1 つに取り組んでいます。
iOS 10 では、DateComponents を通知の開始日として使用できるようになりましたが、複数の通知をどのようにスケジュールして処理するべきかについて、私はちょっと迷っています。
各通知には独自のリクエストが必要であり、次に独自の識別子が必要です。それ以外の場合、複数の通知を作成することはできません。
通知をスケジュールして処理するには、識別子を操作する必要があると考えていましたが、今ではコードが非常に混乱しているため、これを行う簡単な方法がなかったかどうかを真剣に考えていました。
私のデータモデルによると、通知の一意の識別子は次のもので構成されています。
- 私のモデルのID
- 新しい通知が作成されるたびに増加する番号
- 上記はアンダースコアで区切られています
たとえば、ID 3 のオブジェクトに対して 10 件の通知をスケジュールする必要がある場合、次のようになります。3_1, 3_2, 3_3...
通知を受け取るたびに、受け取った通知をループして UI を更新します。また、ユーザーが特定のモデルについて受信した通知を削除したい場合は、同じ ID で始まる識別子をチェックして、受信した通知の一意の識別子をループします。
ドキュメントによると、配信された通知を削除する唯一の方法は識別子を使用することであるため、それ以外の方法でそれを行う方法が実際にはわかりません。UNUserNotificationCenter.current().removeDeliveredNotifications(withIdentifiers:)
問題は、あらゆる種類の問題を引き起こしていることです。簡単に修正できますが、非常にハックに見えます。私は自分がやったことを本当に誇りに思っているわけではなく、それを回避するためのより賢い方法を探しています. それは問題ではないので、意図的にコードを投稿しませんでした。アプローチは本当の問題です。
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
間違いではありませんが、通知がまだ作成されていないだけです...
私はスレッディングの完全な初心者であり、これらの種類の操作に行き詰まっており、どこに行けばよいかわかりません。問題に正しい方法で取り組んでいるかどうかはわかりません。