CloudKitのデータをCSVにExportする方法(Swift5)
iOS アプリを開発するときに、データの格納先としてCloudKit を選択することは多いのではないだろうか。CloudKit はiCloud 上のデータベースで、アプリ単位1PB まで利用できる。
CloudKit Dashboard という管理機能も備え、スキーマやレコードの管理もでき非常に便利なのだが、一つ大きな欠点がある。
CloudKit Dashboard からデータをエクスポートできない
報告や分析するときにデータをエクスポートして加工することは多いのではないだろうか。残念ながらCloudKit Dashboard 上では、そこまでグラフィカルな表現はできず、またデータのエクスポート機能も備えていない。
そこで今回はSwift5 でCloudKit のデータをCSV にExport する方法を書く。
Swift5 でCloudKit のデータをCSV にExport する
ソースコード
private func exportCloudKit(){
let df = DateFormatter()
df.dateFormat = "yyyy-MM-dd HH:mm:ss"
// Change header
var text = "Created,Code,Name\n";
cloudKitLoadRecords() { (records, error) -> Void in
if let error = error {
print(error)
} else {
if let records = records {
for record in records{
// Change Fields
let date = record.creationDate != nil ? df.string(from: record.creationDate!) : ""
let code = record["code"] as! String
let name = record["name"] != nil ? record["name"] as! String : ""
text += date + "," + code + "," + name + "," + "\n"
}
}
let dir = FileManager.default.urls(
for: .documentDirectory,
in: .userDomainMask
).first!
let fileUrl = dir.appendingPathComponent("CloudKitExport.csv")
if FileManager.default.createFile(
atPath: fileUrl.path,
contents: text.data(using: .utf8),
attributes: nil
) {
} else {
print("Failed to create file")
}
print("Processed")
}
}
}
func cloudKitLoadRecords(result: @escaping (_ objects: [CKRecord]?, _ error: Error?) -> Void) {
// Change recordType
let cloudKitQuery = CKQuery(recordType: "Sample", predicate: NSPredicate(value: true))
var records = [CKRecord]()
// If you use Private Database, Chage here 'CKContainer.default().privateCloudDatabase'
let database = CKContainer.default().publicCloudDatabase
var recurrentOperationsCounter = 101
func recurrentOperations(cursor: CKQueryOperation.Cursor?){
let recurrentOperation = CKQueryOperation(cursor: cursor!)
recurrentOperation.recordFetchedBlock = { (record:CKRecord!) -> Void in
recurrentOperationsCounter += 1
records.append(record)
}
recurrentOperation.queryCompletionBlock = { (cursor: CKQueryOperation.Cursor?, error: Error?) -> Void in
if ((error) != nil) {
print(String(describing: error))
result(nil, error)
} else {
if cursor != nil {
recurrentOperations(cursor: cursor!)
} else {
result(records, nil)
}
}
}
database.add(recurrentOperation)
}
var initialOperationCounter = 1
let initialOperation = CKQueryOperation(query: cloudKitQuery)
initialOperation.recordFetchedBlock = { (record:CKRecord!) -> Void in
initialOperationCounter += 1
records.append(record)
}
initialOperation.queryCompletionBlock = { (cursor: CKQueryOperation.Cursor?, error: Error?) -> Void in
if ((error) != nil) {
print(String(describing: error))
result(nil, error)
} else {
if cursor != nil {
recurrentOperations(cursor: cursor!)
} else {
result(records, nil)
}
}
}
database.add(initialOperation)
}
使い方
今回の例では手間を省くためXCode のApp デフォルトで作成されるものをベースに、ContentView.swift に↑のfunc を置いてbody を以下のように変更した。
var body: some View {
List {
}
.toolbar {
Button(action: exportCloudKit) {
Label("export", systemImage: "square.and.arrow.down")
}
}
}
右上のボタンを押すとCSV を出力する。
CSV の出力先は、ユーザ名\ライブラリ\Containers\ツール名\Data\Documents になるので、場所がわからないときはファイル名(CloudKitExport.csv)で検索する。
使うときに変更する箇所
CSV のヘッダ。今回はCreated, Code, Name の3つを出力している
// Change header var text = "Created,Code,Name\n";
出力したいフィールド。値がない可能性があるフィールドは、name のようにnilチェックする
// Change Fields let date = record.creationDate != nil ? df.string(from: record.creationDate!) : "" let code = record["code"] as! String let name = record["name"] != nil ? record["name"] as! String : "" text += date + "," + code + "," + name + "," + "\n"
出力したいRecordType。
// Change recordType let cloudKitQuery = CKQuery(recordType: "Sample", predicate: NSPredicate(value: true))
データベースがPublic かPrivate か
// If you use Private Database, Chage here 'CKContainer.default().privateCloudDatabase' let database = CKContainer.default().publicCloudDatabase
設定方法は後述するが、Production かDevelopment か
ハマったポイント
100レコードまでしか出力されない
最初はperformQuery を使っていたが、100レコードまでしか出力されなかった。CKQueryOperation を使って回す必要があった。
デバッグ実行でProduction からデータを出力したい
特に設定しない場合は、Development からデータが出力された。以下の設定をすることでProduction から出力できた。
- entitlements を開く
- +ボタンを押して、com.apple.developer.icloud-container-environment のキーを追加する
- Type をString 、Value をProduction に設定する。


コメント
コメントを投稿