从主应用或扩展程序更改后刷新核心数据

问题描述 投票:0回答:1

我一直在为我的Core Data应用开发今日的小部件。我将NSFetchedResultsController用于小部件和主应用程序,并使用UserDefaults和此post的帮助从相对的目标更改/添加了数据时收到通知。

但是更新数据或NSFetchedResultsController以查看更改/添加不起作用。我尝试过:

  • NSFetchedResultsController中获取数据
  • 将持久性容器的视图上下文stalenessInterval设置为0并调用viewContext.refreshAllObjects(),然后尝试重新获取数据(有无)
  • 在fetchedController上将shouldRefreshRefetchedObjects设置为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)
}

我使用NSFetchedResultsController使用可扩散的数据源(随iOS 13一起提供),但我不认为这与问题无关,因为我尝试了不使用它,并且发生了相同的问题。

我如何设置核心数据:

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
   }
}
swift core-data nsfetchedresultscontroller today-extension ios-app-group
1个回答
2
投票

您是否已将此内容包含在viewContext设置中?

persistentContainer.viewContext.automaticallyMergesChangesFromParent = true
© www.soinside.com 2019 - 2024. All rights reserved.