CloudKitの概念を整理してみた

iCloudによる安全で簡単に使えるスケーラブルなストレージ

Soudai Sasada

Soudai Sasada

個人でiOSアプリを開発するにあたりある程度の規模のデータを格納したく色々と情報を漁っていたのですがその中でCloudKitについてよく分からない点が多く、日本語で自分が知りたかった情報を見つけることができなかったため自身の頭の整理を兼ねて記事にしてみました。

iCloud storage

CloudKitの説明に入る前にまずiCloudについておさらいをします。

iCloudはApppleが提供するオンラインストレージサービスです。ユーザーはiCloudにデータを保存することでバックアップや別端末との同期を取ることができます。バックアップは3つの種類があります。以下、こちらの記事からの抜粋です。

タイプ 説明
Key-value storage アプリの設定や状態などを保存するためのKVS。最大容量は1アプリ1MB。
iCloud Documents ファイルベースのストレージ(Core Data含む)。ドキュメントやドローファイル、または複雑なアプリの状態などを格納するために利用可能。最大保存容量はユーザーのiCloudアカウントに依存。
CloudKit storage Appleが提供するBaaSの内のストレージ機能。構造化されたデータを管理したり、ユーザー同士で共有したいファイルやデータを保存したい際に利用する。データの管理にはデータベースが使用され、各レコードはKVSとして扱う。

この表から単にiCloudといっても様々な機能がありCloudKitはその中の一つだということが分かります。それではここから本題に移っていきたいと思います。

全体像

CloudKitの各概念の説明に入る前にまずざっくりとCloudKitの全体像について説明します。

CloudKitはその名の通りクラウド上にデータを保存できるAppleによるオンラインストレージサービスであるiCloud上でアプリが利用するデータを保存するためのツールでありサービスです。CloudKitでは役割ごとに領域が分かれていて上位の領域が下位の領域を内包しています。この領域内で扱うデータの種類やポリシーに応じて様々なオプションが用意されているため、開発者はそれらを用途に合わせて選択し組み合わせることでユーザーのニーズに合ったアプリ開発が可能となります。
各領域ごとの大まかな説明は次のとおりです。

領域 説明
Container 名前空間で隔てられた領域
Database 利用可能なアクセスポリシーごとに隔てられた領域
Zone Record(実データ)が保存される領域

iCloudの中にContainerという箱が無数にあり、それぞれのContainerの中にDatabaseが用意され、Database内のZoneにRecordが種類(Record Type)ごとに集まった状態で入っているというイメージです。

それではContainerから順に見ていきます。

Container

ContainerはiCloud内で名前空間ごとに隔てられた領域となりアプリは複数のContainerを利用することができます。Container名はどのような値でも設定できますが iCloud.\(バンドルID) という命名が一般的のようです。もし複数のContainerを利用する場合には公式ドキュメントのように iCloud.\(バンドルID).\(役割A) のようにネームスペースを切っていくのが良さそうです。

CloudKitの利用を開始するにはまずアプリでiCloudを利用するための準備が必要です。
XCodeでSigning & CapabilitiesにあるCapabilityの追加ボタンからメニューを開き、左のサイドメニュー内にあるiCloudを選択することでCloudKitを含むiCloudの機能を利用することができます。
iCloudが利用できるようになったら各機能の中からCloudKitにチェックを入れ、Containerの追加ボタンを押しましょう。ボタン押下時に立ち上がる入力欄ではContainer名だけ入力すれば自動で名前にプレフィックスが割り当てられるため iCloud. というプレフィックスを自身で入力する必要はありません。

Database

DatabaseはContainer内でアクセスレベルによって分けられた領域となっており PublicPrivateShared の3つに分かれます。

種類 読み込み 書き込み 書き込み先
Public 全ユーザー iCloudユーザー 共通領域
Private iCloudユーザー iCloudユーザー ユーザー単位の領域 / 第三者アクセス不可(開発者含む)
Shared iCloudユーザー iCloudユーザー ユーザー単位の領域 / 第三者アクセス可

ここからはそれぞれのデータベースの特性を見ていきます。

Public database

Public databaseは全てのアプリユーザーがデータを読むことができるためiCloudの利用状況に関わらず共通のデータを使用したい場合に適しています。

iCloudにログインしているユーザーはPublic databaseに対し書き込みを行うことができますが、アプリ側で書き込むような機能を実装しなければアプリ開発者のみが(CloudKitのコンソールを通じて)書き込みすることができるためマスターデータを提供するようなことが可能です。

Private database

iCloudにログインしているユーザーが自身のプライベートな領域に読み書きをすることができます。Private databaseはiCloudにログインしているユーザーのみが読み書き可能でアプリ開発者含めた第三者はデータにアクセスすることができないためユーザーが安全にデータを格納するための領域を提供したい場合に適しています。

Shared database

Shared databaseはPrivate databaseと同じようにiCloudにログインしている場合にのみアクセスできユーザーのPrivate databaseのレコードをアプリケーションの他のユーザーと共有するために使用されます。他ユーザーへは読み込み、書き込み、その両方の権限を付与することができます。特定のユーザーのみ公開するようなことはできません。またデータの所有ユーザーが非公開化した場合は他ユーザーはアクセスできなくなります。

Zone

Zoneは CKZone 型のオブジェクトで表現されるデータの保存場所です。各DatabaseにそれぞれZoneが用意されており、実データとなるRecordはここに保存されます。全てのDatabaseにデフォルトのゾーンがありますが、プライベートデータベースのみカスタムゾーンとしてデフォルト以外に複数のZoneを作成することができます。

Security Role

アプリ開発者はSecurity RoleによってPublic databaseのRecordに対しRecord Typeごとにパーミッションを設定することができます。パーミッションは次のとおりです。

パーミッション 説明
Create 作成
Read 読み込み
Write 書き込み(更新)

Security Roleはデフォルトで以下が用意されていてこれらは役割を持っており削除することはできません。また、これらは新たに作成されたRecord Typeにデフォルトで権限を付与します。それぞれの役割とデフォルトで付与される権限は次のとおりです。

名前 説明 デフォルトの権限
_world 全てのユーザー Read
_icloud 全てのiCloudユーザー Create
_creator Recordの作者 Write

Record Type

RecordはZoneの中でスキーマごとに一つの集合として表現されますがそのスキーマがRecord Typeとなります。Record Typeのフィールドは全てのRecordに予め用意されているメタデータと開発者が独自に設定可能なフィールドに分類されメタデータを変更することはできません。
フィールドは名前と型を持ち、また、フィールドごとに複数のIndexを設定することが可能です。

メタデータのフィールドは次のとおりです。

名前 説明
createdTimestamp Date/Time 作成日時
createdUserRecordName Reference 作成ユーザーID
___etag String レコードの変更を検知するためのタグ
modifiedTimestamp Date/Time 最終更新日時
modifiedUserRecordName Reference 最終更新ユーザーID
recordName Reference ID

CloudKitではWebコンソール上にログインしている開発者含めた全ての利用者が Users のRecordです。Recordにはそれぞれ recordName と呼ばれるIDが存在し、createdUserRecordNamemodifiedUserRecordName はそれぞれ作成、更新をしたユーザーの recordName となっており、 Reference 型を使って特定のRecordに対し参照を持つ形で表現されています。
___etag はCloudKit上のRecordを参照しているユーザーが当該Recordへの更新を検知するための値です。Recordをフェッチしたあとにこの値を見て現在参照しているRecordが古いかどうかを確認することができるようになっています。

Index

IndexはRecord TypeごとにRecordをまとめて取得するための仕組みです。Indexは用途によって種類が分かれており各フィールドに対しそれぞれの種類で1つずつ、最大で3つ設定することが可能で、設定可能なフィールドはメタデータを含む全てのフィールドです。

Indexの種類は次のとおりです。

種類 説明
Queryable 指定したフィールドで検索をできるようにします
Searchable 指定したフィールドを全文検索の対象とします
Sortable 指定したフィールドでソートをできるようにします

特定のRecord Typeにおいて検索をするためにはQueryableがいずれか1つ以上のフィールドに設定されている必要があります。これはQueryableが検索をできるようにするためのIndexだからです。また、Queryableで設定したフィールドに対してはフィルタリングの条件指定ができるようになります。

recordName にQueryableを設定した場合のみフィルタリングを設定せずに検索することができましたが、 recordName にはQueryableを指定せずそれ以外のフィールドにQueryableを設定している場合は当該フィールドへのフィルタリングを設定しないと検索することができませんでした。このあたりはなぜなのかよく分かっていません。

Record

Recordは CKRecord 型のオブジェクトでRecord Typeで指定されたフィールドごとにキーと値のペアを持つ辞書のようなデータとなります。

CKRecordのドキュメントはこちらです。

CKRecord

Recordのフィールドに指定可能な型は次のとおりです。

CloudKitの型 Swiftの型 説明
Asset CKAsset 画像や動画、バイナリなどのデータ
Bytes NSData 構造体など(バイナリなどの巨大なデータに使用するのは非推奨)
Location CLLocation 緯度軽度などの位置情報
Double NSNumber 小数(64bit浮動小数点数)
Int(64) NSNumber 整数(64bit符号付き整数)
Reference CKRecord.Reference 別Recordとの関連
String NSString 文字列
Date/Time NSDate 日時

全ての型は配列とすることもできます(Assetの配列やLocationの配列など)。

暗号化

iCloudでは全てのデータがアカウントベースで暗号化されていますがさらに追加の保護レイヤーとしてReference以外の型はiCloudサーバ上で暗号化することができます。暗号化指定された型の値は書き込み時に自動で暗号化され読み込み時に複合化することができます。なおAssetはデフォルトで暗号化されるため指定する必要はありません。
例外としてReferenceのみiCloudサーバ上で見える必要があるため暗号化することができません。

CloudKitのセキュリティについてのドキュメントはこちらです。

CloudKitのセキュリティについて

Reference型

Referenceは特殊で他のRecordへのリンクを作成できRecord間で所有関係を持たせることができ、これにより所有する側のRecordを削除したときに所有される側のRecordを連鎖的に削除することが可能となります。リンクできるのは同一のZone内にあるRecordのみです。

Reference型についてのドキュメントはこちらです。

Reference型について

Subscription

Subscriptionはユーザーがデータの変更をリアルタイムで検知するための仕組みです。購読は種類によってDatabase、Record Zone、Queryの3つに分かれます。

購読の種類 利用可能なDatabase 説明
Database Private / Shared ゾーンごと購読したいがゾーン名が不明な場合に使用
Record Zone Private iCloudユーザー自身のカスタムゾーンを購読したい場合に使用
Query Public / Private クエリの結果を購読したい場合に使用

Subscriptionについてのドキュメントはこちらです。

Subscriptionについて

まとめ

CloudKitの概念について自分が理解できるように整理してみましたが思った以上に骨が折れました。まだまだ理解できていない点が多いのでこれから実際に利用してみて理解を深めていこうと思います。

この記事がお役に立てたら一杯のコーヒーを恵んで頂けると励みになります 😊

Buy Me A Coffee
© 2020, Soudai Sasada