2016-10-01 34 views
0

我想從queryCompletionBlock中檢索一個值並將其發送給另一個viewController如何從完成塊返回值以在其他viewController中使用它?

這是我的代碼:

func KcalCloudKitData() { 
    publicDatabase = container.publicCloudDatabase 
    allRecords = [] 
    let predicate = NSPredicate(value: true) 
    let query = CKQuery(recordType: "Kcal", predicate: predicate) 
    query.sortDescriptors = [NSSortDescriptor(key: "KcalCoef", ascending: true)] 
    let queryOperation = CKQueryOperation(query: query) 

    queryOperation.recordFetchedBlock = {(record: CKRecord) in 
     self.allRecords.append(record) 
    } 

    queryOperation.queryCompletionBlock = {cursor, error in 
     if error != nil { 
      print("Failed loading data from iCloud") 
      //print(error?.localizedFailureReason) 
     } else { 

      for value in self.allRecords { 
       self.kcalUnitValid.append(value.object(forKey: "KcalValidUnit") as! [String]) 
      } 
     //self.performSegue(withIdentifier: "AppLoaded", sender: nil) 
     } 
    } 
    print(self.kcalUnitValid) 
    publicDatabase?.add(queryOperation) 
} 

當我打印使用完成塊外部碼print(self.kcalUnitValid)此獲得一個空表。任何解決方案

在此先感謝。

回答

0

queryCompletionBlock由時間print(self.kcalUnitValid)被稱爲queryCompletionBlock不會完成其執行呢,換句話說,在順序異步執行這樣執行過程如何順序如下:

  • 1.- queryOperation.queryCompletionBlock(..)稱爲
  • 2.- print(self.kcalUnitValid)稱爲// prints empty
  • 3。 - 幾秒鐘後queryOperation.queryCompletionBlock(..)結果返回

代碼

你可以做什麼,它可能是這樣的:

func KcalCloudKitData() { 
    // .. code omitted 
    queryOperation.queryCompletionBlock = {cursor, error in 
    if error != nil { 
     // .. code omitted 
    } else { 
     for value in self.allRecords { 
     self.kcalUnitValid.append(value.object(forKey: "KcalValidUnit") as! [String]) 
     } 

     // Segue to another ViewController 
     // And also sending kcalUnitValid 
     self.performSegue(withIdentifier: "AppLoaded", sender: self.kcalUnitValid) 
    } 
    } 
    // .. code omitted 
} 

// Actually in this method is when you decide 
// what data you are going to send to the AnotherViewController 
override func prepare(for segue: UIStoryboardSegue, sender: Any?) { 
    if segue.identifier == "AppLoaded" { 
    let anotherViewController = segue.destination as! AnotherViewController 
    anotherViewController.kcalUnitValid = sender as! Array<[String]> 
    } 
} 

資源:

Watch this video explaning async programming in Swift

+0

感謝威爾遜的幫助。有效。這是最好的解決方案。 – Patrick

+0

很高興幫助你! – Wilson

0

這是因爲完成關閉(塊是Objective-C的術語)在任務完成後調用:例如,您

self.kcalUnitValid.append(...) 

任務比線

print(self.kcalUnitValid) 

,無論它在控制器中的打印代碼之前表示稍後再進行。

當queryOperation準備好完成時,將觸發完成處理程序。這應該比你的印刷版晚。

所以你應該例如在封閉內打印該值。

queryOperation.queryCompletionBlock = {cursor, error in 
    ... 
     self.kcalUnitValid.append(value.object(forKey: "KcalValidUnit") as! [String]) 

    print(self.kcalUnitValid) 
    ... 
} 

https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Closures.html

+0

謝謝你的幫助pedrouan – Patrick

0

您不能返回從完成塊值,以便使用其他結束塊(作爲方法的參數),並調用它時,你的任務完成類似,

func hardProcessingWithString(input: String, completion: (result: String) -> Void) { 
... 
completion("we finished!") 
} 

你可以使用它,

hardProcessingWithString("commands") { 
(result: String) in 
print("got back: \(result)") 
} 

所以寫一個函數在完成您想要執行的任務時,可以調用它自己的完成處理程序。

參考:

https://thatthinginswift.com/completion-handlers/

https://grokswift.com/completion-handlers-in-swift/

+0

謝謝你的幫助獅子 – Patrick

相關問題