Swift 从主应用程序或扩展程序更改后刷新核心数据
我一直在为我的核心数据应用程序开发“今日”小部件。我对小部件和主应用程序使用Swift 从主应用程序或扩展程序更改后刷新核心数据,swift,core-data,nsfetchedresultscontroller,today-extension,ios-app-group,Swift,Core Data,Nsfetchedresultscontroller,Today Extension,Ios App Group,我一直在为我的核心数据应用程序开发“今日”小部件。我对小部件和主应用程序使用nsfetchedresultscoontroller,并在使用UserDefaults和此应用程序的帮助从相反目标更改/添加数据时收到通知 但是更新数据或NSFetchedResultsController以查看更改/添加不起作用。我试过: 从NSFetchedResultsController重新读取数据 将持久化容器的视图上下文stalenessInterval设置为0,并调用viewContext.refres
nsfetchedresultscoontroller
,并在使用UserDefaults和此应用程序的帮助从相反目标更改/添加数据时收到通知
但是更新数据或NSFetchedResultsController以查看更改/添加不起作用。我试过:
- 从NSFetchedResultsController重新读取数据
- 将持久化容器的视图上下文
设置为0,并调用stalenessInterval
,然后尝试重新提取数据(或不重新提取)viewContext.refreshAllObjects()
- 在fetchedController上将
设置为true时,应将RefreshRefetchedObjects设置为true,以便自动调用
NSFetchedResultsController
:
lazy var fetchedResultsController: NSFetchedResultsController<Item> = setupFetchedController()
override func viewDidAppear(_ animated: Bool) {
loadData()
//check to see if any data was changed. Being notified about changes works every time
subscribeForChangesObservation()
}
private func setupFetchedController() -> NSFetchedResultsController<Item> {
let managedContext = CoreDataManager.sharedManager.persistentContainer.viewContext
let sortDescriptor = NSSortDescriptor(key: "date", ascending: true)
let request : NSFetchRequest<Item> = Item.fetchRequest()
request.predicate = NSPredicate(format: "date <= %@", Date() as NSDate)
request.sortDescriptors = [sortDescriptor]
fetchedResultsController = NSFetchedResultsController(fetchRequest: request, managedObjectContext: managedContext, sectionNameKeyPath: nil, cacheName: nil)
fetchedResultsController.delegate = self
return fetchedResultsController
}
private func loadData() {
do {
try fetchedResultsController.performFetch()
updateSnapshot()
} catch {
print("Hey Listen! Error performing fetchedResultsController fetch: \(error)")
}
}
//reloads the items in the table
func updateSnapshot() {
let fetchedItems = fetchedResultsController.fetchedObjects ?? []
var snapshot = NSDiffableDataSourceSnapshot<Int, Item>()
snapshot.appendSections([0])
snapshot.appendItems(fetchedItems)
dataSource.apply(snapshot, animatingDifferences: true)
}
class CoreDataManager {
static let sharedManager = CoreDataManager()
private init() {}
lazy var persistentContainer: NSPersistentContainer = {
var useCloudSync = UserDefaults.standard.bool(forKey: "useCloudSync")
//Get the correct container
let containerToUse: NSPersistentContainer?
if useCloudSync {
//custom container to just set the defaultDirectoryURL to the app group url
containerToUse = GroupedPersistentCloudKitContainer(name: "App")
} else {
containerToUse = NSPersistentContainer(name: "App")
}
guard let container = containerToUse else {
fatalError("Couldn't get a container")
}
//Set the storeDescription
let storeURL = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: "group.App")!.appendingPathComponent("\(container.name).sqlite")
var defaultURL: URL?
if let storeDescription = container.persistentStoreDescriptions.first, let url = storeDescription.url {
defaultURL = FileManager.default.fileExists(atPath: url.path) ? url : nil
}
if defaultURL == nil {
container.persistentStoreDescriptions = [NSPersistentStoreDescription(url: storeURL)]
}
let description = container.persistentStoreDescriptions.first else {
fatalError("Hey Listen! ###\(#function): Failed to retrieve a persistent store description.")
}
description.setOption(true as NSNumber, forKey: NSPersistentStoreRemoteChangeNotificationPostOptionKey)
if !useCloudSync {
description.setOption(true as NSNumber, forKey: NSPersistentHistoryTrackingKey)
}
container.loadPersistentStores(completionHandler: { (storeDescription, error) in
//migrate from old url to use app groups
if let url = defaultURL, url.absoluteString != storeURL.absoluteString {
let coordinator = container.persistentStoreCoordinator
if let oldStore = coordinator.persistentStore(for: url) {
do {
try coordinator.migratePersistentStore(oldStore, to: storeURL, options: nil, withType: NSSQLiteStoreType)
} catch {
print("Hey Listen! Error migrating persistent store")
print(error.localizedDescription)
}
// delete old store
let fileCoordinator = NSFileCoordinator(filePresenter: nil)
fileCoordinator.coordinate(writingItemAt: url, options: .forDeleting, error: nil, byAccessor: { url in
do {
try FileManager.default.removeItem(at: url)
} catch {
print("Hey Listen! Error deleting old persistent store")
print(error.localizedDescription)
}
})
}
}
}
container.viewContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy
container.viewContext.transactionAuthor = appTransactionAuthorName
// Pin the viewContext to the current generation token and set it to keep itself up to date with local changes.
container.viewContext.automaticallyMergesChangesFromParent = true
do {
try container.viewContext.setQueryGenerationFrom(.current)
} catch {
fatalError("Hey Listen! ###\(#function): Failed to pin viewContext to the current generation:\(error)")
}
// Observe Core Data remote change notifications.
NotificationCenter.default.addObserver(
self, selector: #selector(type(of: self).storeRemoteChange(_:)),
name: .NSPersistentStoreRemoteChange, object: container.persistentStoreCoordinator)
return container
}
}
您是否已将其包括在viewContext设置中
persistentContainer.viewContext.automaticallyMergesChangesFromParent = true
你能展示一下你是如何实现NSFetchedResultsController的吗?你是否使用了FRC的缓存?@rbaldwin刚刚添加了代码!如果你知道如何解决这个问题,请告诉我@pbasdf我不认为我在缓存,因为我在FRCI中保留了cacheName nil,以确保您正在使用查询生成。我对他们不是很熟悉,但你不需要让这一代人接受这些变化吗?谢谢你的回复!不幸的是,我已经在核心数据设置中设置了来自父级的
自动数据管理。我已将我的persistentContainer
设置代码添加到我的问题中,以便您可以看到它。如果你知道如何解决这个问题,请告诉我!!我想不出来