如何从完成块返回值以在其他viewController中使用它?

时间:2016-10-01 12:50:11

标签: ios swift

我想从queryCompletionBlock检索一个值并将其发送给另一个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)打印时,这将获得一个空表。任何解决方案?

提前致谢。

3 个答案:

答案 0 :(得分: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

答案 1 :(得分: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/

答案 2 :(得分: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