iOS15.4/Cloudkit/SwiftUI/database検索サンプル
やっとわかったことがありますのでお伝えいたします。
AppleのCloudKitというものを使用して、databaseを検索する場合、SwiftUI(Swiftでと言っても良いが)で、どのようにコーディングすれば良いか。これでエラーなくコンパイルできて動くというサンプルがわかりましたので、整理しておきます。
解説
① predicateという変数に検索条件を設定しています。IDというのは、私がテスト用に作成したT100_T_SCHOOL というテーブル(Appleでは、テーブルのことをRECORD TYPEと呼ぶ)の中のひとつの項目です(Appleは、項目のことをFieldsと言います。これはOKです)
またソート条件などを設定する箇所も、この部分です。今回の説明上ではあまり重要な部分ではありません。②と③が重要です。
② recordMatchedBlock というメソッドを使用するのがポイントです。
Appleが、このドキュメントでサンプルプロジェクトだとしてしているGitHubのcloudkit-sample-queriesでは、recordFetchedBlockを使用していますが、それはiOS14.1ではOKでしたが、iOSの15.4で使用しようとすると、
'recordFetchedBlock' was deprecated in iOS 15.0: Use recordMatchedBlock instead, which surfaces per-record errors という警告になってしまいます。
同様に、上記サンプルプロジェクトでは ③の部分は、queryCompletionBlockを使用していますが、上記②同様に、iOS14.1ではOKですが、iOS15.4では以下のdeprecate警告が出ます。
'queryCompletionBlock' was deprecated in iOS 15.0: Use queryResultBlock instead
③なので、queryResultBlock を使用することがポイントです。
ソースコードを全文掲載します。
入力パラメータが3つほどありますが、重要なのは3つめのcompletionHandler だけで、その他の2つは私の独自仕様のために必要なパラメータなので無視してけっこうです。
func read_T100(pb_area: User_class,Key searchID: String,completionHandler: @escaping (Result<Void, Error>) -> Void) {
let predicate = NSPredicate(format: "ID == %@", searchID)
let sort = NSSortDescriptor(key: "NAME_OF_SCHOOL", ascending: true)
let query = CKQuery(recordType: "T100_T_SCHOOL", predicate: predicate)
query.sortDescriptors = [sort]
let queryOperation = CKQueryOperation(query: query)
queryOperation.recordMatchedBlock = { record, result in
switch result {
case .success(let record):
DispatchQueue.main.async {
pb_area.T100_Count = pb_area.T100_Count + 1
pb_area.T100_School_Name = record["NAME_OF_SCHOOL"]!
pb_area.T100_Mail_Address = record["MAIL_ADDRESS"]!
print("NAME_OF_SCHOOL = \(record["NAME_OF_SCHOOL"]!)")
print("MAIL_ADDRESS = \(record["MAIL_ADDRESS"]!)")
print("件数 = \(pb_area.T100_Count)")
}
break
case .failure(let error):
print("error内容 = \(error.localizedDescription)")
break
}
}
queryOperation.queryResultBlock = { result in
switch result {
case .failure(let error):
completionHandler(.failure(error))
print("read_T100 Error desu....")
print(error.localizedDescription)
case .success:
print("read_T100 Success desu....")
print("T100件数 = \(pb_area.T100_Count)")
break
}
}
database.add(queryOperation)
}
【テストしてわかった非同期の動き】
①〜③まで及びその周辺あちこちに、display命令を入れまくりまして(すこし残骸が見えると思います)テストを何度もしまして、わかったことがあります。
処理は、あっという間に流れて、このメソッドの後の処理まで流れている時に、②と③の処理はまだ、全く動きません(というか非同期なのでしょう。)
タイミングが、少し遅れて動き出します。レコードに該当があり、該当レコードが戻される度に、②の処理が動きます。そして最後のレコードの②の処理が走行した後に、③の処理が動きました。
かなり勉強になりました。2022.05.19