CloudKit クラウドデータベースに公開情報を保存 (CloudKit Public Database)

## この記事の内容

サーバーに変数を保存してその内容をアプリがフェッチできるようにしたいと思ったことはありませんか？

- 商品の価格
- 掲載された記事のリスト
- その他...

そんな時にぴったりなのが、CloudKit public databaseです。これはAppleから提供されている無料のサービスで、`iOS`、`MacOS`、`JaveScript Web (CloudKit JS)` 環境でのみ利用できます。

## `CloudKit` について

こちらに私の以前の記事から `CloudKit` に関する説明を転載しました。

### 長所

- データをプライベート・データベース、共有データベース、またはパブリック・データベース（すべてのユーザーが他のユーザーのレコードをフェッチできる）に保存できます。
-  CloudKitはAppleの無料クラウドサービスです。
- CloudKitパブリック・データベースへの保存は、割り当て制限に対してカウントされます。
- ユーザーがアプリを削除してから再度インストールすると、CloudKitに保存されているデータをフェッチできます。

### 短所

- ユーザーはオンラインである必要があります。また、CloudKitデータベースの使用にはサイズ制限があります。

https://developer.apple.com/icloud/cloudkit/

## この記事について

この記事では `CloudKit` のパブリックなデータベースについて話します。このデータベース上のデータはアプリのユーザー全員がアクセスすることができます。

ユーザーのプライベートな情報を保存したい場合は、`CloudKit` のプライベートなデータベースが必要です。詳しくは私の[以前の記事](https://qiita.com/MaShunzhe/items/bc21527259c5da7f66ed)をご参照ください

## `CloudKit` の機能を有効化します。次にコンテナを作成します。

私がここで[以前書いた記事のステップ1](https://qiita.com/MaShunzhe/items/bc21527259c5da7f66ed#ステップ1-xcodeプロジェクト設定で必要な機能をオンにするicloudのcloudkitをオンにする)のセクションをお読みください。

その記事のステップ2のところまで来たらこの記事に戻って下さい。

## ステップ2. ユーザー情報を保存するため、CloudKitのデータ構造を設定する。
- 次に"CloudKit Dashboard"ボタンをクリックするか、http://icloud.developer.apple.com へ行く。
- パネル左側にある自分のアプリケーション名をクリックする。

- "Schema" をクリックします

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/635330/6384eeab-c38f-360f-b912-23f9fabe23e9.png)

"New Type" をクリックします

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/635330/ab731121-0348-5694-6a66-ae8260e4b93f.png)

## スキームを追加します

この例では販売する品物とその価格のリストを保存していきます。これが使おうとしているデータスキームです。

| 名称  | 種別  | 数値例  |
|---|---|---|
| itemName  | String  | "ペット小屋"  |
| itemPrice  | Int(64)  | 3000  |

Int(64) が保存できる最大値は 2e63 − 1 です。従って Int(64) を使って価格を保存するのなら問題はないものと思われます。

### `CloudKit` のダッシュボード上にレコードタイプを作成する

- 新規レコードタイプの名称を `Price` としましょう

- 作成した新規レコードタイプを選択してください。`Add Field` をクリックして新規のデータフィールドを追加します：

![image](https://mszmagic.s3-ap-northeast-1.amazonaws.com/qitta_article_publicCloudKit_20200529.png)

- 上記のフィールドを追加してください。手順が完了すると以下のようになります：

![image](https://mszmagic.s3-ap-northeast-1.amazonaws.com/qiita_article_publicCludKit2_20200529.png)

### いま作成したレコードタイプをインデクシング（索引化）可能としてください

公開データベースでデータを閲覧するためには、索引化を有効にする必要があります：

![image](https://mszmagic.s3-ap-northeast-1.amazonaws.com/qitta_article_publicCloudKit3_20200529.png)

`Add Indexes` ボタンをクリックしてください

![image](https://mszmagic.s3-ap-northeast-1.amazonaws.com/qiita_article_publicCloudKit4_20200529.png)

ユーザーの便宜を図るため、ダッシュボードインターフェイスが索引として自動的に `recordName` を選択します。青い `Save Changes` ボタンをクリックするだけで済みます。

### 公開データベースで既存のレコードを取得する

上部の `Schema` ボタンをクリックし、`Data` をクリックしてください

<img width="600" alt="image" src="https://mszmagic.s3-ap-northeast-1.amazonaws.com/qiita_article_publicCloudKit5_20200529.png">

#### 通知: 開発環境を使用しているため、ここで加えた変更は (アプリストアに公開される) プロダクションアプリケーションでアクセス可能ではありません。この記事の後半で、開発からプロダクションにスキームを展開する方法を説明します。また、プロダクション環境で記録を作成する必要があります。

パネルの左側で、データベースを `Public Database` に切り替えてください

<img width="390" alt="image" src="https://mszmagic.s3-ap-northeast-1.amazonaws.com/qitta_article_publicCloudKit6_20200529.png">

そして、タイプを先ほど作成したデータベースのタイプに切り替えます。`Price` です

<img width="390" alt="image" src="https://mszmagic.s3-ap-northeast-1.amazonaws.com/qiita_article_publicCloudKit7_20200529.png">

このタイプのレコードが現在存在しないことが表示されます。`Create New Record` ボタンををクリックして作成してください。

<img width="390" alt="image" src="https://mszmagic.s3-ap-northeast-1.amazonaws.com/qitta_article_publicCloudKit8_20200529.png">

これで、`ペット小屋, 3000` のようなサンプルデータを入力することができます。

<img width="300" alt="image" src="https://mszmagic.s3-ap-northeast-1.amazonaws.com/qiita_article_publicCloudKit9_20200529.png">

そして、下部の青い `Save` ボタンをクリックし、このレコードを保存します。

さて、再び `Query Records` をクリックすると、先ほど作成したレコードが表示されます。

<img width="600" alt="image" src="https://mszmagic.s3-ap-northeast-1.amazonaws.com/qiita_article_publicCloudKit10-20200529.png">

ここで、レコード名（そのデータベースレコードのID）が `31CEB769-8DC1-48FB-69C3-10CFC69C43F6` であることを覚えておいてください。これは後で必要になります。

### (追加ステップ) 新たなレコードタイプを作成してアイテムのコレクションを保持する

これは、私たちが今使っている実例の場合に有効な追加ステップです。この場合、あるアイテム列が含まれるようなデータタイプを新たに一つ作成します。これで、アイテムのコレクションを指し示すそのデータベースのレコードのIDをエンコードできます。さらに、弊社のアプリが一般公開された後でも、そのコレクションを後から更新することが可能になります。

#### コレクションデータタイプの作成:

<img width="600" alt="image" src="https://mszmagic.s3-ap-northeast-1.amazonaws.com/qiita_article_publicCloudKit11_20200529.png">

上記と同じ手順で、このデータタイプにクエリインデックスを追加することも忘れないでください。

#### コレクション・レコードの作成:

上記のレコードIDを使用して、アイテムのコレクションを含むレコードを作成します。

<img width="300" alt="image" src="https://mszmagic.s3-ap-northeast-1.amazonaws.com/qiita_article_publicCloudKit12_20200529.png">

このレコードの名前は `88F7E1D5-F8C5-5CEC-1253-27937513CB46` であることを覚えておいてください。

### アプリでレコードにアクセスする

さて、これらのレコードをiOSアプリで取得します:

#### レコードをフェッチするには

```swift
func fetchItem(itemID: String) {
    let db = CKContainer(identifier: "iCloud.com.[アプリiCloudコンテナーの名前]").publicCloudDatabase
    let recordID = CKRecord.ID(recordName: itemID)
    db.fetch(withRecordID: recordID) { (obtainedRecord, error) in
        if let itemName = obtainedRecord?.value(forKey: "itemName") as? String,
            let itemPrice = obtainedRecord?.value(forKey: "itemPrice") as? Int64 {
            print("Item Name \(itemName) with price \(itemPrice)")
        }
    }
}
```

`fetchItem(itemID: "31CEB769-8DC1-48FB-69C3-10CFC69C43F6")` を呼び出すと以下の結果が得られます：

```
Item Name ペット小屋 with price 3000
```

#### アイテムのコレクションをフェッチするには

```swift
func fetchCollections() {
    let appCollectionID = "88F7E1D5-F8C5-5CEC-1253-27937513CB46"
    let db = CKContainer(identifier: "iCloud.com.[アプリiCloudコンテナーの名前]").publicCloudDatabase
    let recordID = CKRecord.ID(recordName: appCollectionID)
    db.fetch(withRecordID: recordID) { (fetchedCollection, error) in
        if let itemIDs = fetchedCollection?.value(forKey: "itemRecordIDs") as? [String] {
            for itemID in itemIDs {
                fetchItem(itemID: itemID)
            }
        }
    }
}
```

さて、このファンクションを再び実行すると、以下のアウトプットを得ます：

```swift
Item Name ぬいぐるみ with price 3500
Item Name ペット小屋 with price 3000
```

### プロダクションにデプロイする

最後にはiCloudの開発用データベースを本番環境にデプロイする必要があります。

![image](https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F635330%2F82288f3a-2f0f-23cd-e1ba-c8ca51002883.png?ixlib=rb-1.2.2&auto=format&gif-q=60&q=75&w=1400&fit=max&s=7679fede712226f77bc924ad6fd09bb8)

#### 通知: 開発環境を使用しているため、ここで加えた変更は (アプリストアに公開される) プロダクションアプリケーションでアクセス可能ではありません。プロダクション環境で記録 (Record) を作成する必要があります。

### デバッグのオプション

`CloudKit` 環境をデバッグする方法はいくつかあります

#### ライブログ

`CloudKit` ダッシュボードで、一番上のドロップダウンメニューをクリックして `Log` を選択します

![image](https://mszmagic.s3-ap-northeast-1.amazonaws.com/qiita_article_publicCloudKit13_20200529.png)

#### 環境の切り替え

シミュレーターでもプロダクション環境への切り替えが可能です。

`Core Data` を `CloudKit` と使う際にはよい方法ではないかもしれません。`Core Data` がローカルの `Core Data` のデータベース構造と`Cloudkit` を同期することを妨げる可能性があるからです。

プロダクション環境を使うには、`.entitlement` ファイルを探し、以下のラインを加えます。

```swift
<key>com.apple.developer.icloud-container-environment</key>
<string>Production</string>
```

---

:relaxed: [Twitter @MszPro](https://twitter.com/MszPro)

:sunny: [私の公開されているQiita記事のリストをカテゴリー別にご覧いただけます。](http://mszpro.com/ioskiji/)
<img width="150" src="https://cdn.mszmagic.com/static-web-content/AppClipImage_small.png">