iOS 今日扩展与核心数据

标签 ios swift xcode core-data today-extension

我正在尝试为我的 iOS 应用程序制作一个 Today 扩展。 今天的扩展将根据核心数据保存的数据显示“下一个”类(class)。 我一直在做一些研究,我知道我必须与 appGroup 共享我的 permanentContainer。 所以我这样做了:

  • 为 iOS 应用和 Today 扩展目标启用了 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)
    }
}

然后在我的核心数据堆栈中:

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 在两个目标之间共享。 此时,我认为我可以从扩展程序访问我的核心数据,但是当我执行获取请求时,我没有得到任何结果。该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")
    }
}

我也尝试直接发出获取请求,但结果得到一个空数组。 为什么我没有得到任何结果?

另一件事:我使用 nsfetchedResult Controller 以便每次从 ios 应用程序更新数据时刷新 View 数据,这样可以吗还是我应该使用 widgetPerformUpdate 方法?在这种情况下,我们不知道今天的扩展何时会刷新,并且它可能会显示过时的数据。

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

最佳答案

您应该像下面这样子类化 NSPersistentCloudKitContainer,返回 defaultDirectoryURL() 的应用程序组 URL。然后在您的CoreDataStack中,使用let container = GroupedPersistentCloudKitContainer(name: "SchoolCompanion")。同时删除对 addToAppGroup(...) 的调用。您需要在应用程序和扩展程序中实例化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!
    }
    ...
}

关于iOS 今日扩展与核心数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60476017/

相关文章:

swift - 如何快速检测标签栏索引变化?

ios - 回到之前的 ViewController 不适用于 Swift 中的多个 View Controller

swift - 如何通过 ssh/NMSSH 模拟 key

ruby - 安装 Pod 时出错 - 0x00000001045b8000 处的总线错误

ios - boundingRectWithSize为UILabel添加了额外的底部填充

ios - Swift xcode 横线

android - 使用空气将视频从手机流式传输到 FMS

ios - 无法使用类型为 'enumerate' 的参数列表调用 '(String)'

swift - 在 Swift 中声明字典的不同方法?

ios - 如何将按钮设置到导航的最右侧 - iOS