Соединение CKQueryNotification со SwiftUI
Я пытаюсь получить фоновые уведомления о подписке из общедоступной базы данных CloudKit самым простым способом. У меня проблемы с тем, что именно должно быть внутри функции, которая обрабатывает пожары подписки и добавляет их в тип коллекции, будь то в didReceiveRemoteNotification или где-то еще. Список @State должен отражать список записей базы данных, но я не уверен, как мне это сделать. Я пробовал использовать @EnvironmentObject и некоторые другие способы, но к нему ничего не было добавлено. В приведенном ниже коде, когда я добавляю новую запись, я получаю только: ЕСТЬ НИЧЕГО ДО: [] ЕСТЬ НИЧЕГО ПОСЛЕ: [] Однако это не означает, что я не получаю объект записи. Я понимаю, но список остается []. Сейчас меня больше всего интересует fetchRecord(), предназначенная для вновь созданных записей.
Я хочу, чтобы список автоматически добавлял новейший заголовок и отображал его на экране каждый раз, когда я создаю новую запись из панели управления CloudKit или где-то еще.
Наконец, это тихие уведомления, а не push-уведомления. Спасибо и будьте в безопасности!
ContentView
import SwiftUI
import CloudKit
struct ContentView: View {
let publicData = CKContainer.default().publicCloudDatabase
@State var list: [String] = []
func fetchData() {
let query = CKQuery(recordType: "OLALA", predicate: NSPredicate(value: true))
self.publicData.perform(query, inZoneWith: nil, completionHandler: { (records, error) in
guard let records = records else { return }
DispatchQueue.main.async {
for record in records {
if let title = record.object(forKey: "title") as? String {
self.list.append(title)
}
}
}
})
}
func subscribe() {
let subscription = CKQuerySubscription(recordType: "OLALA", predicate: NSPredicate(value: true), options: [.firesOnRecordDeletion, .firesOnRecordUpdate, .firesOnRecordCreation])
let info = CKSubscription.NotificationInfo()
info.shouldSendContentAvailable = true
subscription.notificationInfo = info
self.publicData.save(subscription) { (savedSubscription, error) in
if error != nil {
print(error!.localizedDescription)
} else {
print("Subscribed!")
}
}
}
func deleteSubscriptions() {
publicData.fetchAllSubscriptions { subscriptions, error in
if error == nil {
if let subscriptions = subscriptions {
for subscription in subscriptions {
self.publicData.delete(withSubscriptionID: subscription.subscriptionID) { str, error in
if error != nil {
print(error!.localizedDescription)
}
}
}
}
} else {
print(error!.localizedDescription)
}
}
}
func fetchRecord(record: CKRecord.ID) {
self.publicData.fetch(withRecordID: record) { (record, error) in
if error != nil {
print(error!.localizedDescription)
} else {
DispatchQueue.main.async {
if let title = record?.object(forKey: "title") as? String {
print("IS THERE ANYTHING BEFORE: \(self.list)")
self.list.append(title)
print("IS THERE ANYTHING AFTER: \(self.list)")
}
}
}
}
}
func deleteRecord(record: CKRecord.ID) {
self.publicData.fetch(withRecordID: record) { (record, error) in
if error != nil {
print(error!.localizedDescription)
} else {
DispatchQueue.main.async {
if let title = record?.object(forKey: "title") as? String {
if let index = self.list.firstIndex(of: title) {
self.list.remove(at: index)
}
}
}
}
}
}
var body: some View {
VStack {
HStack {
Button(action: {
self.fetchData()
}, label: {
Text("Fetch")
})
Spacer()
Button(action: {
self.list.removeAll()
}, label: {
Text("Clear")
})
Spacer()
Button(action: {
self.subscribe()
}, label: {
Text("Subscribe")
})
Spacer()
Button(action: {
self.deleteSubscriptions()
}, label: {
Text("Delete subs")
})
}.padding(.vertical, 40)
.padding(.horizontal, 20)
List(self.list, id: \.self) { title in
Text(title)
}
}
}
}
AppDelegate:
import UIKit
import CoreData
import CloudKit
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
print("\n\nTOKEN TAKEN\n\n")
}
func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
}
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
//let dict = userInfo as! [String : NSObject]
let notification = CKQueryNotification(fromRemoteNotificationDictionary: userInfo)
if notification?.queryNotificationReason == .recordCreated {
ContentView().fetchRecord(record: (notification?.recordID)!)
}
if notification?.queryNotificationReason == .recordUpdated {
//later
}
if notification?.queryNotificationReason == .recordDeleted {
ContentView().deleteRecord(record: (notification?.recordID)!)
}
}
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
UIApplication.shared.registerForRemoteNotifications()
return true
}
...
}