Core Data by tutorials 笔记(五)

我们继续来看《Core Data by Tutorials》这本书的第七章 Syncing with iCloud,本章所讨论的是 iOS 8 和 Yosemite 最新释出的 iCloud Drive,至于 iCloud Drive 与 iCloud 的区别可以看这里,调试本章code需要一个开发者帐号:)

Chapter 7: Syncing with iCloud

一、CloudNotes

iCloud 是基于 Core Data 的,之前几个版本确实做的比较烂,不过苹果也在不断地改进。本章的代码其实就是在第六章代码的基础上改为 Cloud 版本。

二、Enabling iCloud

iCloud 对 core data store 同步其实使用的是 ubiquity containers(无处不在的容器),这个 无处不在的容器 存在你应用的 sandbox 中,并由 iOS 系统替你管理。如同向 NSFileManager 请求应用的 Documents directory,对于 iCloud 来说,请求的是一个 ubiquity container URL

Core Data 通过这个 ubiquity container URL 保存应用程序的数据,他和通过 URL 保存到 Documents 没什么区别。唯一不同的就是 iCloud 后台进程监视着 ubiquity container 里面文件的变化,时刻准备上传到云端,而这一切都是系统自动完成的。

这里需要注意的是,iCloud 的运行机制有点类似与 Git,每次同步的其实是 transaction logs,而不是 data store 本身。而与 Git 不同的是, commit 的时候,Git 经常需要处理冲突。但 iCloud 的 commit change 是 “atomic” 的,意味着,要么数据全部有效,要么全部丢弃。

作者这里用伦敦桥搬家举了一个很形象的例子,把桥拆成一砖一砖,然后搬到目的地再按照log记录的正确顺序重组。iCloud 的工作机制也差不多。

在 Xcode 中将 Capabilities 中的 iCloud 启用。这里可以使用默认的ubiquity container,也可以自定义。

三、The cloud stack

.addPersistentStoreWithType方法的参数option数组增加一个成员NSPersistentStoreUbiquitousContentNameKey,同样地在stack的初始化中设置。

lazy var stack : CoreDataStack = {  
    let options = [NSPersistentStoreUbiquitousContentNameKey: "CloudNotes",
        NSMigratePersistentStoresAutomaticallyOption: true,
        NSInferMappingModelAutomaticallyOption: true]
    let stack = CoreDataStack(modelName: "CloudNotesDataModel", 
        storeName: "CloudNotes",
        options: options)
    return stack 
}()

使用 NSPersistentStoreUbiquitousContentNameKey 的值 CloudNotes,在 ubiquity container 中来唯一标识该应用的 persistent store。

到此为止,已经为该 APP 完全开启了 iCloud 同步,很简单吧。但 Core Data 在背后还是做了一些工作的,其中一项就是设置了一个 fallback store,用于在 iCloud 离线时保存数据。不过开发者完全不用担心这些东西。

四、Testing iCloud

至于测试则需要拥有一个开发者帐号,登录 itunesconnect,依次选择 Users and Roles >> Sandbox Testers 新建一个测试用户,这里注意的是,新建完的测试帐号需要在真机设备上激活一下。

具体的测试也很简单,现在模拟器上运行起来,可以看到目前所有添加的数据,然后切换 target device(并不按下停止键)选择真机设备 Run 一下,此时模拟器和真机会同时运行。此时在模拟器上创建新的记录,并选择 Debug\Trigger iCloud Sync 来触发同步,不久应该就能看到新添加的记录在真机上出现。作者还展示了 iCloud gauge 的方式来查看具体的同步记录。

现在可以来总结一下设置 iCloud 的基本步骤了,主要有三步:

  1. 启用 iCloud 并且设置 ubiquity containers。
  2. 通过设置 persistent store 的 options 来启用 iCloud-Core Data 同步。
  3. 当 app 运行时,设置 app 响应新的变化。

前两步已经说过了,现在来看第 3 点。

五、Responding to iCloud changes

该实例程序使用的是 fetched results controller,而 fetched results controller 主要又依赖的是 NSManagedObjectContext。但是 iCloud 更新是直接在 persistent store 级别的,不会经过 Context。因此也不会触发 fetched results controller 的代理方法来更新 UI。

既然如此,我们需要知道 iCloud 何时更新可以通过监听广播的方法来实现,通过监听 NSPersistentStoreDidImportUbiquitousContentChangesNotification 广播,来刷新 context(通过mergeChangesFromContextDidSaveNotification(notification))

六、Switching iCloud accounts

当前账户登出的话,Core Data 会删除当前数据(都安全保存在云端,会在用户重新登录时同步回来)。帐号切换时,Core Data 会发送如下两个通知:

  • NSPersistentStoreCoordinatorStoresWillChangeNotification
  • NSPersistentStoreCoordinatorStoresDidChangeNotification

the notification 会包含具体要被 adding/addedremoving/removedNSPersistentStore objects

  1. 当Core Data 发出 NSPersistentStoreCoordinatorStoresWillChangeNotification 时,Core Data stack 会保存当前所有数据到当前 store 中,这样用户帐号登出了不会丢失任何数据。接着重置 managed object context。
  2. 当 Core data 发出 “did change” notification 时, the notes list controller 需要重为新登录的帐号的或本地存储的数据源刷新 View。

先处理 “will change” notification:

func persistentStoreCoordinatorWillChangeStores( notification: NSNotification){  
    var error : NSErrorPointer = nil if context.hasChanges {
        if context.save(error) == false { 
            print("Error saving \(error)")
        } 
    }
    context.reset() 
}

再处理 “did change” notification

func persistentStoreCoordinatorDidChangeStores(notification:NSNotification){  
    notes.performFetch(nil)
    tableView.reload()
}

-EOF-

如果感觉此文对你有帮助,请随意打赏支持作者 😘

chengway

认清生活真相之后依然热爱它!

Subscribe to Talk is cheap, Show me the world!

Get the latest posts delivered right to your inbox.

or subscribe via RSS with Feedly!