我有一个名为NSManagedObject
的Event
,该代码在主机应用和今日扩展程序之间共享。 (在“目标成员身份”中,同时选中了主应用程序和小部件)。
主机应用程序和窗口小部件具有相同的应用程序组标识符,并且都共享Data Model
(在目标成员身份中,同时检查了主应用程序和窗口小部件)。
当我在Xcode中启动(运行)窗口小部件时,它将显示已保存在宿主应用程序中的所有应用程序事件(Event
)。但是,当我添加一个新事件时,它会出现在主机应用程序中,但不会出现在Today-widget中。如果我重新启动窗口小部件,则会显示所有事件,包括以前没有的最后一个事件。
这是获取事件的方法。它在小部件的TodayViewController
中定义。
private func fetchEvents(date: Date) {
let predicates = NSCompoundPredicate(andPredicateWithSubpredicates: [
NSPredicate(format: "date = %@",Date().startOfDay as CVarArg),
NSPredicate(format: "startTime >= %@", Date() as CVarArg)
])
if let ev = try? TPEvent.fetchAll(predicates: predicates, in: persistentManager.context) {
events = ev
}
}
此事件在viewWillAppear
和widgetPerformUpdate
中调用。
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
fetchEvents(date: Date())
self.tableView.reloadData()
}
func widgetPerformUpdate(completionHandler: (@escaping (NCUpdateResult) -> Void)) {
self.fetchEvents(date: Date() )
self.tableView.reloadData()
completionHandler(NCUpdateResult.newData)
}
persistentManaged.context
是PersistentManager.shared.context
(请参见下面的代码)。
顺便说一下,当我查看Today-widget时,上述两种方法都被调用。我有很多时间弄清楚这个问题,但无法解决。
[如果您需要更多信息或有任何疑问,请发表评论。
我有一个单例PersistentManager
。在主机应用程序和小部件中都使用viewContext
。
public final class PersistentManager {
init() {}
public static let shared = PersistentManager()
public lazy var persistentContainer: NSPersistentContainer = {
let container = NSPersistentCloudKitContainer(name: "Event")
guard let fileContainer = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: "group.event.data") else {
fatalError("Shared file container could not be created.")
}
let storeURL = fileContainer.appendingPathComponent("Event.sqlite")
let storeDescription = NSPersistentStoreDescription(url: storeURL)
container.persistentStoreDescriptions = [storeDescription]
container.loadPersistentStores(completionHandler: { (storeDescription, error) in
if let error = error as NSError? {
fatalError("Unresolved error \(error), \(error.userInfo)")
}
})
container.viewContext.automaticallyMergesChangesFromParent = true
do {
try container.viewContext.setQueryGenerationFrom(.current)
} catch {
fatalError("###\(#function): Failed to pin viewContext to the current generation:\(error)")
}
return container
}()
public lazy var context = persistentContainer.viewContext
// MARK: - Core Data Saving support
public func saveContext () {
let context = persistentContainer.viewContext
if context.hasChanges {
do {
try context.save()
} catch {
let nserror = error as NSError
fatalError("Unresolved error \(nserror), \(nserror.userInfo)")
}
}
}
}
在iOS上发送进程间通知的一种隐藏方法是在NSUserDefaults
对象上使用KVO。
在NSUserDefaults.h
头文件中,苹果指出
/ *!每当在当前进程中更改任何用户默认值时,都会发布NSUserDefaultsDidChangeNotification,而在普遍存在的默认值更改时或外部进程更改默认值时,则不会发布NSUserDefaultsDidChangeNotification。使用键值观察为感兴趣的特定键注册观察者将通知您所有更新,无论它们来自何处。* /
[具有此指定,可以假设通过在Combine
的特定键上使用KVO(甚至在Swift上甚至是UserDefaults
),值更改将从应用程序传播到扩展程序,反之亦然。
因此,方法可以是在主应用程序中的每个更改上,将更改的当前时间戳保存到UserDefaults
中:
/// When the change is made in the main app:
let defaults = UserDefaults(suiteName: "group.<your bundle id>")
defaults["LastChangeTimestamp"] = Date()
defaults.synchronize()
在应用程序扩展中:
func subscribeForChangesObservation() {
let defaults = UserDefaults(suiteName: "group.<your bundle id>")
defaults?.addObserver(self, forKeyPath: "LastChangeTimestamp", options: [.new, .initial], context: nil)
}
override class func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
// Process your changes here.
}