简体   繁体   English

带有核心数据的 iOS 今日扩展

[英]iOS today extension with core data

I am trying to make a today extension for my ios app.我正在尝试为我的 ios 应用程序制作今天的扩展。 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.我一直在做一些研究,我知道我必须与 appGroup 共享我的persistentContainer。 So I did :所以我做了 :

  • enabled appGroups for both ios app and today extension targets.为 ios 应用程序和今天的扩展目标启用了 appGroups。
  • coded a function to share it :编写了一个函数来共享它:
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)")
            }
        }
    }
}

that files and the xcdatamodel are shared between both targets.该文件和 xcdatamodel 在两个目标之间共享。 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.在这一点上,我以为我可以从我的扩展程序访问我的核心数据,但是当我执行 fetch 请求时,我没有得到任何结果。 The controllerDidChangeContent is never executed. controllerDidChangeContent 永远不会被执行。

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 ?为什么我没有得到任何结果?

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 ?另一件事:我使用 nsfetchedResult 控制器以便在每次从 ios 应用程序更新数据时刷新视图数据,这样可以吗,还是应该使用 widgetPerformUpdate 方法? In that case we don't know when the today extension will be refreshed and it may dispay outdated data.在这种情况下,我们不知道今天的扩展何时会被刷新,它可能会显示过时的数据。

main documentation used : https://www.avanderlee.com/swift/core-data-app-extension-data-sharing/使用的主要文档: https : //www.avanderlee.com/swift/core-data-app-extension-data-sharing/

You should subclass NSPersistentCloudKitContainer like below, returning the App Group URL for defaultDirectoryURL() .您应该像下面那样子类化 NSPersistentCloudKitContainer,返回defaultDirectoryURL()的应用程序组 URL。 Then in your CoreDataStack , use let container = GroupedPersistentCloudKitContainer(name: "SchoolCompanion") .然后在您的CoreDataStack 中,使用let container = GroupedPersistentCloudKitContainer(name: "SchoolCompanion") Also remove, your call to addToAppGroup(...) .同时删除您对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.您需要在应用程序和扩展中实例化GroupedPersistentCloudKitContainer ,您还需要确保GroupedPersistentCloudKitContainer链接到两个目标。

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!
    }
    ...
}

The url for your app group is here:您的应用组的网址在这里:

let url = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: "SchoolCompanion)

The sqlite-file is there. sqlite 文件在那里。 You don't need Cloud container.您不需要云容器。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM