Origheart

CloudKit初探

什么是CloudKit

  • iCloud
  • Documents
  • iCloud Drive
  • CloudKit

CloudKit 基础对象类型

  • CKContainer: Containers 就像应用运行的沙盒一样,一个应用只能访问自己沙盒中的内容而不能访问其他应用的。Containers 就是最外层容器,每个应用有且仅有一个属于自己的 container。

  • CKDatabase: Database 即数据库,私有数据库用来存储敏感信息,比如说用户的性别年龄等,用户只能访问自己的私有数据库。应用也有一个公开的数据库来存储公共信息,例如你在构建一个基于地理位置的应用,那么地理位置信息就应该存储在公共数据库里以便所有用户都能访问到。

  • CKRecord: 即数据库中的一条数据记录。CloudKit 使用 record 通过 key-value 结构来存储结构化数据。关于键值存储,目前值的架构支持 NSString、NSNumber、NSData、NSDate、CLLocation,和 CKReference、CKAsset(这两个下面我们会说明),以及存储以上数据类型的数组。

  • CKRecordZone: Record 不是以零散的方式存在于 database 之中的,它们位于 record zones 里。每个应用都有一个 default record zone,你也可以有自定义的 record zone。

  • CKRecordIdentifier: 是一条 record 的唯一标识,用于确定该 record 在数据库中的唯一位置。

  • CKReference: Reference 一种引用关系。以地理位置签到应用为例,每个地理位置可以包含很多用户在该位置的签到,那么位置与签到之间就形成了这样一种包含式的从属关系。

  • CKAsset: 即资源文件,例如二进制文件。还是以签到应用为例,用户签到时可能还包含一张照片,那么这张照片就会以 asset 形式存储起来。

    有哪些Api(Diary Demo)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
func updateRecord(diary: Diary, record: CKRecord) {
record.setObject(diary.content, forKey: "Content")
record.setObject(diary.created_at, forKey: "Created_at")
if let location = diary.location {
record.setObject(location, forKey: "Location")
}
if let title = diary.title {
record.setObject(title, forKey: "Title")
}
record.setObject(diary.id, forKey: "id")
privateDB.saveRecord(record, completionHandler: { (newDiary, error) -> Void in
debugPrint("Diary Updated")
if let error = error {
debugPrint("error \(error.description)")
}
})
}

1
2
3
4
5
func deleteCloudRecord(record: CKRecord) {
privateDB.deleteRecordWithID(record.recordID) { (recordID, error) -> Void in
print("Delete \(recordID?.recordName) \(error?.description)")
}
}

查询 -> 修改 -> 更新

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
func fetchCloudRecordWithTitle(title: String , complete: ([CKRecord]?) -> Void) {
let predicate = NSPredicate(format: "Title == %@", title)
let query = CKQuery(recordType: "Diary",
predicate: predicate )
privateDB.performQuery(query, inZoneWithID: nil) {
results, error in
if let results = results {
complete(results)
} else {
complete(nil)
}
}
}

碰到的问题(踩到的坑)

  1. Saving CloudKit Record “Not Authenticated” (9/1002)“ ”This request requires an authenticated account
    原因:使用模拟器或者设备没有启用iCloud
  2. Couldn't get container configuration from the server for container
    原因:container’s identifier错误,可能是使用默认值,也可能是与代码里初始化container时的identifier不一致;
    另外,需要与开发者中心Certificates, Identifiers & Profiles的iCloud Containers保持一致。需要5分钟左右才可以使用
  3. Invalid Arguments(12/2015); server message = Field '___recordID' is not marked queryable
    原因:未设置Metadata Indexes.需要前往CloudKit Dashboard -> Record Types -> Metedata Indexes设置

收费

等不及要试试 CloudKit 了?它能让你从编写服务端代码、监控服务器压力、长期维护大量的 CDN、租用服务器等等等等的事情中解脱出来。等等!CloudKit 怎么收费呢,会很贵吗?答案是:免费。目前苹果允许你使用 CloudKit 存储 10 GB 资源,100 M 数据库存储,每天 2 GB 流量;当你的用户数量增加的时候,这些免费额度也相应地增加到 1 PB 存储、10 TB 数据库存储,以及每天 200 TB 流量。

Demo

https://github.com/Origheart/apps/tree/master/CloudKitDemo

参考

官方文档
iCloud Dashboard
NSHipster