2017-08-05 21 views
0

私は、CloudKitにレコードを保存するアプリケーションを作成しており、そのデータをCore Dataにローカルに保存しています。私は実際に両方の場所にレコードを保存することができますが、iCloudへの接続が利用できない場合や保存エラーが発生した場合にエラーを処理できる必要があります。私はCKModifyRecordsOperationコンプリートブロック内の変数を差別化するための変数を設定できると考えましたが、それはうまくいかない - プロセスが成功しても、CloudKitの保存からの戻り値は常に偽です。最初にCloudKitに保存してから、recordIDを取得し、コアデータの保存で保存します。CloudKitからBoolを返すCompletionHandlerが正しくない

ここに私のコードがありますが、私はをbarbuttonから呼び出します。コンソールの出力はコードの下にあります。アドバイスをいただければ幸いです。 Xcodeの8.3.3、スウィフト3、iOSの10

func saveNewCloudKitRecord() -> Bool { 

    privateDatabase = container().privateCloudDatabase 
    recordZone = CKRecordZone(zoneName: "myPatientZone") 

    var blockSavedToCloudKit = false 

    let myRecord = CKRecord(recordType: "Patient", zoneID: (recordZone?.zoneID)!) 
    myRecord.setObject(firstNameTextField.text as CKRecordValue?, forKey: "firstname") 
    myRecord.setObject(lastNameTextField.text as CKRecordValue?, forKey: "lastname") 
    let parentRefID = CKRecordID(recordName: "047EBE6C-AB1C-0183-8D80-33C0E4AE228B", zoneID: (recordZone?.zoneID)!) 
      // 
    //bunch more record fields 
    // 

    let modifyRecordsOperation = CKModifyRecordsOperation(recordsToSave: [myRecord], recordIDsToDelete: nil) 
    modifyRecordsOperation.timeoutIntervalForRequest = 10 
    modifyRecordsOperation.timeoutIntervalForResource = 10 

    modifyRecordsOperation.modifyRecordsCompletionBlock = { 

     records, recordIDs, error in 

     if let err = error { 
      blockSavedToCloudKit = false 
      //create placeholder record name for later updating 
     } else { 
      blockSavedToCloudKit = true 
      self.currentRecord = myRecord 
      self.passedInCKRecord = myRecord 
     }//if err 

    }//modifyRecordsOperation 

    privateDatabase?.add(modifyRecordsOperation) 

    print("blockSavedToCloudKit is \(blockSavedToCloudKit)") 
    return blockSavedToCloudKit 

}//saveNewCloudKitRecord 


typealias SavedCompletion = (_ success:Bool) -> Void 

func saveTwoFiles(completionHandler : SavedCompletion) { 

    let flag = saveNewCloudKitRecord() 
    print("flag is \(flag)") 

    completionHandler(flag) 
    print("completionHandler(flag) is \(flag)") 
}//makeTheComboSave 

func doTheComboSave() { 

    saveTwoFiles() { (success) -> Void in 

     print("saveTwoFiles is \(success)") 

     if success { 
      //will pass the CKRecord so core data can store the recordID and recordName 
      saveTheNewRecord()//this is the Core Data save 

      DispatchQueue.main.async { 
       self.performSegue(withIdentifier: "unwindToMasterViewController", sender: self) 
       print("Completion block has been run successfully.") 
      }//Dispatch 

     } else { 
      //create placeholder recordName for later updating 
      saveTheNewRecord()//this is the Core Data save 
      DispatchQueue.main.async { 
       self.performSegue(withIdentifier: "unwindToMasterViewController", sender: self) 
       print("Completion block has been run but the file save to CloudKit failed.") 
      }//Dispatch 


     }//if else 
    }//block 

}//doTheComboSave 

コンソール出力:

blockSavedToCloudKitがある偽

フラグがfalse

saveTwoFilesある偽

completionHandler(ありますフラグ)は偽です

完了ブロックは実行されましたが、CloudKitに保存されたファイルは失敗しました。

modifyRecordsOperation

で成功

currentRecordNameです:B53DCFB8-0EFB-4E79-8762-FECCEFBA9BD8

+0

CloudKit /ネットワークコールの非同期性を理解していないと思います。 saveNewCloudKitRecordから返されたfalseは、操作が完了する前に返されます。あなたは、あなたがあなたの例で期待する方法を返すために、障壁またはセマフォーを必要とします。 – agibson007

答えて

0

上記Ichydonからのコメントを参照してください。

saveHandlerが使用したいブール値を設定する前にsaveNewCloudKitRecord()関数が戻ります。全体的なアイデアは、最初にCloudKitレコードを作成して、ローカルデータとクラウドレコードを同期させるためにcoreNameに格納するrecordNameを取得できるようにすることでした。

より良い方法は、最初にコアデータに保存することですが、自分自身でCKRecordIDを作成し、それをCloudKitに保存するときにレコードにフィードします。コアデータレコードを保存する機能で

let myRecordName = UUID().uuidString 

は、[保存CloudKitのためのパラメータとして使用するために、その文字列を返します。

let myRecordID : CKRecordID = CKRecordID(recordName: myRecordName, zoneID: (recordZone?.zoneID)!) 

let myRecord = CKRecord(recordType: "Whatever", recordID : myRecordID) 

これは他の人に役立つことを望みます。

関連する問題