背景播种/加载iOS核心数据存储

时间:2016-01-02 13:39:01

标签: ios multithreading swift core-data

我的 iOS 8.0 + 应用程序本质上是一个字典应用程序,以索引,易于导航的格式向用户呈现只读数据集。我已经探索了几种加载静态数据的策略,并且我决定在应用程序首次打开时,为应用程序提供一些序列化并加载到JSON存储中的Core Data个数据文件。因此,对managedObjectContext.save()的调用只会在首次使用时在应用的生命周期内发生一次。

通过阅读 Mac开发者库中的 Apple Core Data Programming Guide(2015年9月更新),我了解 Apple&#39 ; s 建议的做法是:1)将Core Data堆栈与AppDelegate分隔为dedicated DataController object(这使得它看起来很奇怪在 Xcode 7.2 中,Core Data堆栈默认仍然放在AppDelegate中,但无论如何......);和
2)打开(并且,我假设,种子/加载)background thread中具有dispatch_async块的持久性存储,如下所示:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0)) {
    //(get URL to persistent store here)

    do {
        try psc.addPersistentStoreWithType(NSSQLiteStoreType, configuration: nil, URL: storeURL, options: nil)

        //presumably load the store from serialized JSON files here?
    } catch { fatalError("Error migrating store: \(error)") }
}

我刚刚开始学习并发性和 GCD ,所以我的问题是基本的:

1)如果数据集正在后台线程中加载,这可能需要一些非常重要的时间来完成,初始view controller如何知道数据何时完成加载以便它可以获取数据从ManagedObjectContext开始显示UITableView

2)沿着类似的路线,如果我想通过运行一些提取并将调试文本打印到控制台来测试完全加载的数据集,我怎么知道后台处理何时完成并且它是安全的开始查询?

谢谢!

p.s。我正在 swift 中进行开发,因此任何特定于swift的提示都会非常有用。

2 个答案:

答案 0 :(得分:1)

您可以import the data yourself,然后添加只读.sqlite文件,而不是尝试让您的应用在首次启动时导入只读数据(强制用户在导入数据时等待);数据模型到您的应用目标,将被复制到应用包。

对于导入,请指定持久性存储应使用回滚日记选项,因为不建议对只读存储使用预写日志记录:

let importStoreOptions: [NSObject: AnyObject] = [
    NSSQLitePragmasOption: ["journal_mode": "DELETE"],]

在实际应用中,还指定捆绑的持久性存储应使用只读选项:

let readOnlyStoreOptions: [NSObject: AnyObject] = [
    NSReadOnlyPersistentStoreOption: true,
    NSSQLitePragmasOption: ["journal_mode": "DELETE"],]

由于捆绑的持久存储是只读的,因此可以直接从应用程序包中访问它,甚至不需要从捆绑包中复制到用户目录。

答案 1 :(得分:0)

不考虑在第一次启动时加载JSON是否是最佳选择,并且这个问题已经存在四年了,解决这两个问题的方法可能是使用通知。它们在所有线程中工作,并且将通知每个侦听类实例。另外,您只需要添加两行:

  1. 侦听器(问题2的视图控制器或测试类)需要侦听特定通知名称的通知:

    NotificationCenter.default.addObserver(自身,选择器:#selector(ViewController.handleMySeedNotification(_ :)),名称:“ com.yourwebsite.MyCustomSeedNotificationName”,对象:无)

其中@objc func handleMySeedNotification(_ notification: Notification)是您要实现的功能,它将在收到通知时执行应发生的一切。

  1. 调用者(您的数据库逻辑)在成功导入数据时发送通知。看起来像这样:

    NotificationCenter.default.post(名称:“ com.yourwebsite.MyCustomSeedNotificationName”,对象:无)

这就足够了。我个人喜欢使用Notification.Name的扩展名,以便更快地访问名称并防止输入错误。这是可选的,但如下所示:

extension Notification.Name {
    static let MyCustomName1 = Notification.Name("com.yourwebsite.MyCustomSeedNotificationName1")
    static let MyCustomName2 = Notification.Name("CustomNotificationName2")
}

现在,使用它们变得像这样简单:NotificationCenter.default.post(name: .MyCustomSeedNotificationName1, object: nil),甚至在键入点后也能完成代码!