前提・実現したいこと
A データベース(CloudKit)のレコードから配列を取得
B 配列に要素を追加
C その配列をデータベースに保存
Aが終わったらB、Bが終わったらC、という処理を書きたいです。
発生している問題
以下の関数を実行しますと、
Aに時間がかかるため、取得前にB、その後すぐCが実行されてしまい、
結果として1つのnewPlanID
だけがデータベースに保存されます。
Swift
1let publicDatabase = CKContainer.default().publicCloudDatabase 2 3func addPlanIDToDatabase(accountID: String, newPlanID: String) { 4 5 var planIDsOnDatabase = [String]() 6 7 // ↓---------- A データベースのレコードから配列を取得 ---------- 8 9 let recordID = CKRecord.ID(recordName: "accountID-(accountID)") 10 11 publicDatabase.fetch(withRecordID: recordID, completionHandler: {(record, error) in 12 13 if let error = error { 14 print("予定ID一覧取得エラー: (error)") 15 return 16 } 17 18 if let planIDs = record?.value(forKey: "planIDs") as? [String] { 19 20 for planID in planIDs { 21 planIDsOnDatabase.append(planID) 22 } 23 } else { 24 print("(accountID)のデータベースの予定なし") 25 } 26 }) 27 28 // ↓---------- B 配列に要素を追加 ---------- 29 30 planIDsOnDatabase.append(newPlanID) 31 32 // ↓---------- C その配列をデータベースに保存 ---------- 33 34 let predicate = NSPredicate(format: "accountID == %@", argumentArray: [accountID]) 35 let query = CKQuery(recordType: "Accounts", predicate: predicate) 36 37 publicDatabase.perform(query, inZoneWith: nil, completionHandler: {(records, error) in 38 39 if let error = error { 40 print("(accountID)のデータベースの予定ID追加エラー1: (error)") 41 return 42 } 43 44 for record in records! { 45 46 record["planIDs"] = planIDsOnDatabase as [String] 47 48 self.publicDatabase.save(record, completionHandler: {(record, error) in 49 50 if let error = error { 51 print("(accountID)のデータベースの予定ID追加エラー2: (error)") 52 return 53 } 54 55 print("(accountID)のデータベースの予定ID追加成功") 56 }) 57 } 58 }) 59}
例えばデータベースに"001"があり、そこに"002"を追加して保存したい場合、こんな感じになっています。
理想
A "001"を取得。planIDsOnDatabase = ["001"]
B "002"を追加。planIDsOnDatabase = ["001", "002"]
C planIDsOnDatabase = ["001", "002"]
を保存。
現実
A "001"を取得する途中で。planIDsOnDatabase = [String]()
B "002"を追加。planIDsOnDatabase = ["002"]
C planIDsOnDatabase = ["002"]
を保存する処理開始。
その後、Aが終わってplanIDsOnDatabase = ["002", "001"]
となる。
試したこと
直列処理を書いてみたのですが、知識不足でうまくいきませんでした。
Swift
1let publicDatabase = CKContainer.default().publicCloudDatabase 2 3func addPlanIDToDatabase(accountID: String, newPlanID: String) { 4 5 var planIDsOnDatabase = [String]() 6 7 // ↓---------- A データベースのレコードから配列を取得 ---------- 8 9 let dispatchQueue = DispatchQueue(label: "queue") // 直列キュー 10 11 dispatchQueue.async { 12 13 let recordID = CKRecord.ID(recordName: "accountID-(accountID)") 14 15 self.publicDatabase.fetch(withRecordID: recordID, completionHandler: {(record, error) in 16 17 if let error = error { 18 print("予定ID一覧取得エラー: (error)") 19 return 20 } 21 22 if let planIDs = record?.value(forKey: "planIDs") as? [String] { 23 24 for planID in planIDs { 25 planIDsOnDatabase.append(planID) 26 } 27 } else { 28 print("(accountID)のデータベースの予定なし") 29 } 30 }) 31 } 32 33 // ↓---------- B 配列に要素を追加 ---------- 34 35 dispatchQueue.async { 36 planIDsOnDatabase.append(newPlanID) 37 } 38 39 // ↓---------- C その配列をデータベースに保存 ---------- 40 41 dispatchQueue.async { 42 43 let predicate = NSPredicate(format: "accountID == %@", argumentArray: [accountID]) 44 let query = CKQuery(recordType: "Accounts", predicate: predicate) 45 46 self.publicDatabase.perform(query, inZoneWith: nil, completionHandler: {(records, error) in 47 48 if let error = error { 49 print("(accountID)のデータベースの予定ID追加エラー1: (error)") 50 return 51 } 52 53 for record in records! { 54 55 record["planIDs"] = planIDsOnDatabase as [String] 56 57 self.publicDatabase.save(record, completionHandler: {(record, error) in 58 59 if let error = error { 60 print("(accountID)のデータベースの予定ID追加エラー2: (error)") 61 return 62 } 63 64 print("(accountID)のデータベースの予定ID追加成功") 65 }) 66 } 67 }) 68 } 69}
また、Timer
で監視して値が変わったら次の処理を……という記述もしてみたのですが、
処理が重くなる上に邪道と思いますので、できれば正当な方法を望みます。
直列処理、もしくは他の正当な手段を知っている方がいらっしゃいましたら、どうぞよろしくお願いいたします。
補足情報(FW/ツールのバージョンなど)
Xcode 11.6
Swift 5
ここまで読んでくださり、ありがとうございます。
質問に至らぬ点があるかもしれませんが、どうぞよろしくお願いいたします。
回答1件
あなたの回答
tips
プレビュー
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2020/10/11 05:52