我正在开发一个在自身和Notification Service Extension之间使用共享Core Data数据库的应用程序。应用程序和扩展都能够读取和写入相同的Core Data数据库。
但是,一旦数据库中的相应字段发生更改,应用程序就需要更新显示的信息。有没有一种有效的方法来通知扩展对该数据库所做的更改?我假设应用程序和扩展使用不同的托管上下文来访问数据库。还是我错了?
答案 0 :(得分:1)
使用SwiftEventBus
这很简单
Controller.swift
let yourObj = YourObject()
SwiftEventBus.post("EventName", sender: yourObj)
Extension.swift
let yourObj = YourObject()
SwiftEventBus.post("EventName", sender: yourObj)
AppDelegate.swift
SwiftEventBus.onMainThread(self, name: "EventName") { (result) in
if let yourObject = result.object as? YourObject {
// Queue or write the data as per your need
}
}
答案 1 :(得分:0)
我指出@CerlinBoss使用通知后,发现了解决的问题的解决方案。可以从扩展名向应用程序发送通知(反之亦然)。这可以在iOS中使用Darwin通知中心来完成。但是,限制是您不能使用通知将自定义数据发送到您的应用程序。
阅读了许多文章后,我决定避免通过两个不同的过程并使用多个托管上下文对Core Data数据库进行更改。相反,我将需要传达给应用程序的数据放入UserDefaults的一个键中,一旦通知应用程序更改,我便将它们出队并更新Core Data上下文。
import os
import Foundation
open class UserDefaultsManager {
// MARK: - Properties
static let applicationGroupName = "group.com.organization.Application"
// MARK: - Alert Queue Functions
public static func queue(notification: [AnyHashable : Any]) {
guard let userDefaults = UserDefaults(suiteName: applicationGroupName) else {
return
}
// Retrieve the already queued notifications.
var alerts = [[AnyHashable : Any]]()
if let data = userDefaults.data(forKey: "Notifications"),
let items = NSKeyedUnarchiver.unarchiveObject(with: data) as? [[AnyHashable : Any]] {
alerts.append(contentsOf: items)
}
// Add the new notification to the queue.
alerts.append(notification)
// Re-archive the new queue.
let data = NSKeyedArchiver.archivedData(withRootObject: alerts)
userDefaults.set(data, forKey: "Notifications")
}
public static func dequeue() -> [[AnyHashable : Any]] {
var notifications = [[AnyHashable : Any]]()
// Retrieve the queued notifications.
if let userDefaults = UserDefaults(suiteName: applicationGroupName),
let data = userDefaults.data(forKey: "Notifications"),
let items = NSKeyedUnarchiver.unarchiveObject(with: data) as? [[AnyHashable : Any]] {
notifications.append(contentsOf: items)
// Remove the dequeued notifications from the archive.
userDefaults.removeObject(forKey: "Notifications")
}
return notifications
}
}
override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) {
self.contentHandler = contentHandler
bestAttemptContent = (request.content.mutableCopy() as? UNMutableNotificationContent)
if let bestAttemptContent = bestAttemptContent {
os_log("New notification received! [%{public}@]", bestAttemptContent.body)
// Modify the notification content here...
// Queue the notification and notify the application to process it
UserDefaultsManager.queue(notification: bestAttemptContent.userInfo)
notifyApplication()
contentHandler(bestAttemptContent)
}
}
func notifyApplication() {
let name: CFNotificationName = CFNotificationName.init("mutableNotificationReceived" as CFString)
if let center = CFNotificationCenterGetDarwinNotifyCenter() {
CFNotificationCenterPostNotification(center, name, nil, nil, true)
os_log("Application notified!")
}
}
// Subscribe to the mutableNotificationReceived notifications from the extension.
if let center = CFNotificationCenterGetDarwinNotifyCenter() {
let name = "mutableNotificationReceived" as CFString
let suspensionBehavior = CFNotificationSuspensionBehavior.deliverImmediately
CFNotificationCenterAddObserver(center, nil, mutableNotificationReceivedCallback, name, nil, suspensionBehavior)
}
let mutableNotificationReceivedCallback: CFNotificationCallback = { center, observer, name, object, userInfo in
let notifications = UserDefaultsManager.dequeue()
for notification in notifications {
// Update your Core Data contexts from here...
}
print("Processed \(notifications.count) dequeued notifications.")
}