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

fph*_*elp 5 core-data nsfetchedresultscontroller swift ios-app-group today-extension

我一直在为我的核心数据应用程序开发一个今日小部件。我NSFetchedResultsController对小部件和主应用程序使用 a ,并在使用 UserDefaults 和这篇文章的帮助从相反目标更改/添加数据时收到通知。

但是更新数据或NSFetchedResultsController查看更改/添加不起作用。我努力了:

  • 从重新获取数据NSFetchedResultsController
  • 将持久容器的视图上下文设置stalenessInterval为 0 并调用viewContext.refreshAllObjects()then 尝试重新获取数据(并且不重新获取数据)
  • shouldRefreshRefetchedObjects在 fetchedController 上设置为 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)
}
Run Code Online (Sandbox Code Playgroud)

我使用 diffable 数据源(随 iOS 13 一起推出)NSFetchedResultsController,但我认为这与问题没有任何关系,因为我尝试不使用它,但发生了同样的问题。

我如何设置核心数据:

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
   }
}
Run Code Online (Sandbox Code Playgroud)

Ely*_*Ely 2

您是否已将其包含在 viewContext 设置中?

persistentContainer.viewContext.automaticallyMergesChangesFromParent = true
Run Code Online (Sandbox Code Playgroud)