今日iOS扩展与核心数据 [英] iOS today extension with core data
问题描述
我正在尝试为我的ios应用进行今天的扩展。
今天的扩展程序将基于与核心数据一起保存的数据显示下一个课程。
我一直在做一些研究,我知道我必须与appGroup共享我的persistentContainer。
所以我这样做了:
I am trying to make a today extension for my ios app. That today extension will display the 'next' Course based on data saved with core data. I've been doing some research and I understand I have to share my persistentContainer with an appGroup. So I did :
- 为ios应用程序和今天的扩展目标启用了appGroup。
- 编写了一个共享它的函数:
public extension NSPersistentContainer {
func addToAppGroup(id: String) {
guard let fileContainer = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: id) else {
fatalError("Shared file container could not be created.")
}
let storeURL = fileContainer.appendingPathComponent("\(self.name).sqlite")
let storeDescription = NSPersistentStoreDescription(url: storeURL)
self.persistentStoreDescriptions.append(storeDescription)
}
}
然后在我的核心数据栈中:
then in my core data stack :
internal class CoreDataContainer {
static var persistentContainer: NSPersistentContainer = {
let container = NSPersistentCloudKitContainer(name: "SchoolCompanion")
container.addToAppGroup(id: "group.com.Ce-dricLoneux.School-Companion")
container.loadPersistentStores(completionHandler: { (_, error) in
if let error = error as NSError? {
fatalError("Unresolved error \(error), \(error.userInfo)")
}
})
return container
}()
// MARK: - Core Data Saving support
func saveContext () {
let context = CoreDataContainer.persistentContainer.viewContext
if context.hasChanges {
do {
try context.save()
} catch {
let nserror = error as NSError
fatalError("Unresolved error \(nserror), \(nserror.userInfo)")
}
}
}
}
文件和xcdatamodel在两个目标之间共享。
此时,我以为可以从扩展名访问我的核心数据,但是当我执行提取请求时,没有任何结果。
that files and the xcdatamodel are shared between both targets. At this point I thought I could access my core data from my extension but when i do a fetch request I don't get any result. The controllerDidChangeContent is never executed.
class TodayViewController: UIViewController, NCWidgetProviding {
private func configureFetchedResultsController() {
let request: NSFetchRequest<Course> = Course.fetchRequest()
request.sortDescriptors = []
self.fetchedResultsController = NSFetchedResultsController<Course>(fetchRequest: request, managedObjectContext: CoreDataContainer.persistentContainer.viewContext, sectionNameKeyPath: nil, cacheName: nil)
self.fetchedResultsController.delegate = self
do {
try self.fetchedResultsController.performFetch()
} catch {
print(error.localizedDescription)
}
}
override func viewDidLoad() {
super.viewDidLoad()
self.extensionContext?.widgetLargestAvailableDisplayMode = .compact
self.configureFetchedResultsController()
}
func widgetPerformUpdate(completionHandler: (@escaping (NCUpdateResult) -> Void)) {
// Perform any setup necessary in order to update the view.
// If an error is encountered, use NCUpdateResult.Failed
// If there's no update required, use NCUpdateResult.NoData
// If there's an update, use NCUpdateResult.NewData
completionHandler(NCUpdateResult.newData)
}
}
// MARK: - FetchedResultsController Delegate
extension TodayViewController: NSFetchedResultsControllerDelegate {
func controllerDidChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
print("content did change")
}
}
我也尝试使提取请求不明确,但结果得到一个空数组。
为什么我没有得到任何结果?
I tried to make a fetch request direclty too, buti get an empty array as result. Why does I don't get any result ?
另一件事:每次从ios应用程序更新数据时,我都使用nsfetchedResult控制器来刷新视图数据,因此可以还是应该使用widgetPerformUpdate方法?在那种情况下,我们不知道今天的扩展将何时刷新,并且它可能会支付过期的数据。
Another thing : i used nsfetchedResult controller in order to refresh the view data each time the data is updated from the ios app so is that ok or should I use the widgetPerformUpdate method ? In that case we don't know when the today extension will be refreshed and it may dispay outdated data.
使用的主要文档: https://www.avanderlee.com/swift/core-data-app-extension-data-共享/
推荐答案
您应该像下面这样子类化NSPersistentCloudKitContainer,返回的应用组网址defaultDirectoryURL()
。然后在您的 CoreDataStack 中,使用 let container = GroupedPersistentCloudKitContainer(name: SchoolCompanion)
。同时删除对 addToAppGroup(...)
的调用。您需要在应用程序和扩展程序中实例化 GroupedPersistentCloudKitContainer ,还需要确保 GroupedPersistentCloudKitContainer 链接到两个Target。
You should subclass NSPersistentCloudKitContainer like below, returning the App Group URL for defaultDirectoryURL()
. Then in your CoreDataStack, use let container = GroupedPersistentCloudKitContainer(name: "SchoolCompanion")
. Also remove, your call to addToAppGroup(...)
. You will need to instantiate the GroupedPersistentCloudKitContainer in both the App and the Extension, you will also need to make sure the GroupedPersistentCloudKitContainer is linked to both Targets.
class GroupedPersistentCloudKitContainer: NSPersistentCloudKitContainer {
enum URLStrings: String {
case group = "group.com.yourCompany.yourApp"
}
override class func defaultDirectoryURL() -> URL {
let url = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: URLStrings.group.rawValue)
if !FileManager.default.fileExists(atPath: url!.path) {
try? FileManager.default.createDirectory(at: url!, withIntermediateDirectories: true, attributes: nil)
}
return url!
}
...
}
这篇关于今日iOS扩展与核心数据的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!