CloudKitを使ってみた Swift版


CloudKitとは、iCloudのデータベースにアクセスするためのライブラリです。Apple標準のアプリ(Mail, Contact, Note, News)で使用しており、複数のデバイスにインストールされたアプリケーションでデータの共有が可能です。(Push通知)
AWSのように、無料枠(Free Tier)と有料枠があります。JavaScript版もあります。

## Xcodeから新規にプロジェクトを作成します

`Capabilities`から、`iCloud`をONにします。`CloudKit`をチェックします。
(もちろん、iCloudにアクセスするため、AppleIDが必要になります。)
プロジェクトナビゲータに、CloudKitライブラリが追加されます。
![MyCloudKit2_xcodeproj.jpg](https://qiita-image-store.s3.amazonaws.com/0/75231/356b4178-ea34-e963-1054-3c0155756577.jpeg)

`CloudKit`をインポートします。

```swift:CloudTableViewController.swift
import UIKit
import CloudKit

class CloudTableViewController: UITableViewController {

```

データベースには、パブリックとプライベートの2種類あります。パブリックは誰からも参照できます。書込みはオーナーのみです。
Personsテーブル(３つのString型カラム)に、レコードをインサートしてみます。
key-valueで設定します。(開発環境では、スキーマを前もって作らなくても大丈夫です。)

```swift:CloudTableViewController.swift
    // Prepare a record to insert.
    let doc = CKRecord(recordType: "Persons")
            
    doc["name"] = alert.textFields?.first?.text ?? "no name"
    doc["address"] = "Okinawa Naha"
    doc["tel"] = "080-123-4567"
            
    // Get a Public DB
    let collection = CKContainer.defaultContainer().publicCloudDatabase
    // Save a record
    collection.saveRecord(doc, completionHandler: { (record:CKRecord?, error:NSError?) in
        if let error = error {
            print("Error occurred: \(error)")
            return
        }
    })

```

実行します。シミュレータが起動したら、いったん設定画面を開き、iCloudにログインします。再度、実行し直します。

![Screenshot_5_19_16__9_31_AM.jpg](https://qiita-image-store.s3.amazonaws.com/0/75231/ecac1bf5-26dc-bbd0-a40e-ed7cdb2e7ea4.jpeg)


iCloudダッシュボートを`Safari`で開きます。
https://icloud.developer.apple.com/dashboard/

`Default Zone`メニューから、レコードがインサートされたのが確認できます。

![CloudKit_Dashboard.jpg](https://qiita-image-store.s3.amazonaws.com/0/75231/03052709-90c7-7023-6c59-60d62679a585.jpeg)

次に、プログラムからテーブルの検索をしてみます。
それにはまず、`Record Type`から、`Persons`を選択し、`Metadata Indexes` >`RecordID`>`Query`をチェックする必要があります。
![Screen Shot 2016-05-19 at 11.48.25 PM.png](https://qiita-image-store.s3.amazonaws.com/0/75231/801348a0-d38b-6e06-25ae-66449a6df206.png)

コードです。`NSPredicate`で検索条件を指定できます。ここでは、全件検索しています。

```swift:CloudTableViewController.swift
    var items = [CKRecord]()

    func loadData() {
        let collection = CKContainer.defaultContainer().publicCloudDatabase
        let query = CKQuery(recordType: "Persons", predicate: NSPredicate(format: "TRUEPREDICATE", argumentArray: nil))
        
        // submit a query
        collection.performQuery(query, inZoneWithID: nil) { (records:[CKRecord]?, error:NSError?) in
            if let error = error {
                print("query: \(error)")
            }
            if let records = records {
                self.items = records
                dispatch_async(dispatch_get_main_queue(), { 
                    self.tableView.reloadData()
                })
            }
        }
    }
```

ダッシュボードから使用状況(アクセスユーザ数、リクエスト数、データ使用量)などをグラフで確認することもできます。

![CloudKit_Dashboard.jpg](https://qiita-image-store.s3.amazonaws.com/0/75231/2b96af0c-d384-735d-1174-8b79beb79c88.jpeg)

## ソート機能

レコードを作成した日時 [CreationDate](https://developer.apple.com/library/ios/documentation/CloudKit/Reference/CKRecord_class/#//apple_ref/doc/uid/TP40014044-CH1-SW14)の降順でソートします。
ダッシュボード から、`Metadata Indexes > Date Created > Sort` をチェックします。
画面右下にある`Save`をクリックして保存します。

![CloudKit_Dashboard.jpg](https://qiita-image-store.s3.amazonaws.com/0/75231/9696ee3f-4483-2c93-c290-a8ca595b0ac1.jpeg)

コードを下記のように修正します。

```swift:CloudTableViewController.swift
    func loadData() {
        let collection = CKContainer.defaultContainer().publicCloudDatabase
        let query = CKQuery(recordType: "Persons", predicate: NSPredicate(format: "TRUEPREDICATE", argumentArray: nil))
        // Sort Persons order by 'creationDate' desc
        query.sortDescriptors = [NSSortDescriptor(key: "creationDate", ascending: false)]

```

## 検索条件の指定

検索条件に使用するPredicateに関しては、下記のページのObjective-Cの説明を参考にします。

https://developer.apple.com/library/ios/documentation/CloudKit/Reference/CKQuery_class/

![CKQuery_Class_Reference.jpg](https://qiita-image-store.s3.amazonaws.com/0/75231/90e7f8b7-de55-085c-0019-106818738251.jpeg)

カラム`name`が、`David` に完全マッチするレコード

```swift
let predicate = NSPredicate(format: "name == %@", "David")
```

カラム`tel`が、`080`で始まるレコード。(tel like '080%')

```swift
let predicate = NSPredicate(format: "tel BEGINSWITH %@", "080")
```

カラム`name`が、`David` or `Taylor` に完全マッチするレコード

```swift
let predicate = NSPredicate(format: "name IN %@", ["David", "Taylor"] )
```

## 参考
Brian AdventさんのYouTube
https://www.youtube.com/watch?v=XQ3nLV2778U
https://www.youtube.com/watch?v=BXl5o5_2aEU

CocoaHeadsさんのYouTube
https://www.youtube.com/watch?v=Io94KVQovBk
Apple公式ページ
https://developer.apple.com/library/ios/documentation/DataManagement/Conceptual/CloudKitQuickStart/Introduction/Introduction.html