iOS15.4/Cloudkit/SwiftUI/database 追加処理(複数項目)サンプル

Apple様が、ドキュメントサンプルプロジェクトだとしてしているGitHubcloudkit-sample-queriesの中のAdd処理(レコード追加処理)では、追加しようとするテーブルContactには、項目がひとつしかありません。(項目名 name です)

一般的なテーブルには、2つ以上の項目がありますので、サンプルは、そのまま使えません。

私が、上記サンプルをもとにさせていただき、項目が2つ以上テーブルにある場合の追加処理を自分なりに作成したものを公開いたします。

上記のように、テーブルには、ID, MAIL_ADDRESS, NAME_OF_SCHOOL と3つの項目があるものとします。

IDは、ある固定値を使うとして、残りの2項目の値が上記のように、2個ずつ用意できたとします。
1レコード目には、"Takahashi School"と"takahashi@abb.com"が挿入される予定です。
@Published は、私のプログラムの都合なので、気にしないで下さい。

まず処理の呼び出し部分ですが

Project全体を見ないとなんのことかわからないと思いますが、そこは上記Apple指示のサンプルを見ていることを前提とさせていただくことで、ご容赦ください。

修正前のソースは

Button("Add", action: { self.vm.saveContacts([name]) { _ in
self.isAddingContact = false
self.vm.refresh() ....

という部分なのですが、入力引数が、入力欄がひとつしかないにも関わらず、nameという変数に入力された変数を、わざわざ配列に [name] というようにして、渡しています。受け取り側も配列で受け取っていたのですが、このままでは、1テーブルに一つの項目しかないアプリにしか対応できません。私は、入力(追加)すべき項目値は、別に用意(上で説明済み)して、引数では渡さないことにしました。pb_area という引数が見えますが、これは、published している領域を引数で渡す処理で、これ自体はあまり重要事項ではありません。

必要な処理だけ残し、不要な処理を除くと、 { _ in } の部分が残りました。
これ自体を削除すると、以下のコンパイルエラーになります。

Missing argument for parameter 'completionHandler' in call

呼び出し先 function の最後のパラメータに、
... , completionHandler: @escaping (Result<[CKRecord]?, Error>) -> Void)
と、確かに 'completionHandler' を使っているのですが、この { _ in } 記述が必要な理由を全く論理的に説明できない。(理解するのに、おそらく1年ぐらいかかるのではないか。笑)

                   

では、本題のdatabaseへの追加(挿入)処理記述ですが、以下のようになっております。

(ここに説明を追加します)

① 修正前のプログラムでは、概ね
let records = p1.map { createT100Record(forName1: $0) }
と書いてあった部分です。やっていることは、レコードを作りたい値を持っている部分を入力として、入力レコード(の配列)を records というCKRecord形式という形で、複数個配列として作り上げることです。

①(青字)部分:データ挿入をしようとする1レコードを作成しようとしている処理。この処理は、入力のindexが0番目のときと1番めを指しているときの2回Callされる。予め用意してあるpb_areaのメールアドレスと学校名の配列領域から index番目をデータもととして(挿入前)レコードを作り上げて、returun文で、戻す。

② CKModifyRecordsOperationをCallすることで、databaseにデータを挿入しようとする命令の発行。

③ 実行が終了すると、一回だけ呼ばれる(DB追加が非同期なので、④の走行の後に③がの実行結果が来る。)

ソースコードを全文掲載します。

     func saveT100(pb_area:User_class, completionQueue: DispatchQueue = .main, completionHandler: @escaping (Result<[CKRecord]?, Error>) -> Void) {
             
        //let records = p1.map { createT100Record(forName1: $0,pb_area:pb_area) }
    
        var records:[CKRecord] = []
        for idx in 0...pb_area.T100_School_Name.count-1 {
            records.append(createT100Record(index:idx,pb_area:pb_area))
        }
        
        print("saveT100 records件数 = \(records.count)")

        let saveOperation = CKModifyRecordsOperation(recordsToSave: records)
        saveOperation.savePolicy = .allKeys

        saveOperation.modifyRecordsResultBlock = { result in
            switch result {
            case .success:
                completionHandler(.success(records))
            case .failure(let error):
                self.reportError(error)
            }
        }
        database.add(saveOperation)
    }

    private func createT100Record(index: Int,pb_area:User_class) -> CKRecord {
        
        let recordID = CKRecord.ID(zoneID: contactsZoneID)
        let record = CKRecord(recordType: "T100_T_SCHOOL", recordID: recordID)
                
        record["ID"] = self.i_CloudKit_UserId
        record["MAIL_ADDRESS"] = pb_area.T100_Mail_Address[index]
        record["NAME_OF_SCHOOL"] = pb_area.T100_School_Name[index]
        return record
    }
   

2022.05.20 J-Souma