如何在单个函数中执行两个完成块并将完成块的数据传递给下一个视图控制器?

How to execute two completion blocks in a single function and pass the data of the completion block to next view controller?

这是我的数据库结构:

我正在使用带闭包的函数,执行两个完成块并将数据存储在两个单独的数组中。获得数据后,我想将数据传递给下一个视图控制器到不同的变量中,但我得到的是两个数组的相同值。

@IBAction func GoToAnswerPage(_ sender: Any) {

    self.getData(refe:JoinCodeTextField.text!) { (array) in
        self.performSegue(withIdentifier:"JoinToAnswerPage",sender:array)
    }

}

func getData(refe: String, completion: @escaping (([Any]) -> ())) {
    var questionArray = [Any]()
    var answerArray = [Any]()
    let ref = Database.database().reference(fromURL: "https://pollapp-30419.firebaseio.com/").child("Questions/\(refe)/")
    ref.child("Question_And_Options").observeSingleEvent(of: .value,with: { snapshot in
        let enumerator = snapshot.children
        while let rest = enumerator.nextObject() as? DataSnapshot, let value = rest.value{
            questionArray.append(value)
        }
        completion(questionArray)
    })
    ref.child("Answer_Key").observeSingleEvent(of: .value,with: { snapshot in
        let enumerator = snapshot.children
        while let rest = enumerator.nextObject() as? DataSnapshot, let value = rest.value{
            answerArray.append(value)
        }
        completion(answerArray)
    })
}

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    guard let joinViewController = segue.destination as? JoinAnswerViewController
        else {
            return
    }
    joinViewController.answers = sender as! [String]
    joinViewController.options = sender as! [String]
}

在下一个视图控制器上。

var options = [Any]()
var answers = [Any]()

这是我得到的输出:

answers-["Test Q-1", "Test A-1", "Test A-2"]

questions-["Test Q-1", "Test A-1", "Test A-2"]

answers-["Test A-1"]

questions-["Test A-1"]

相反,我应该得到:

questions-["Test Q-1", "Test A-1", "Test A-2"]

answers-["Test A-1"]

您的完成处理程序将被调用两次,一次针对 "answers",一次针对 "questions"。它们可以按任意顺序出现,因此您应该在完成时额外传递一个 type 以了解您收到了哪个。使用 [String : [Any]] 字典收集两个数组,并在收到两个数组并将它们存储在字典 arrays.

中时调用 self.performSegue(withIdentifier:sender:)

prepare(for:sender:) 中解压缩 sender 字典并分配值:

@IBAction func GoToAnswerPage(_ sender: Any) {

    var arrays = [String : [Any]]()

    self.getData(refe: JoinCodeTextField.text!) { (array, type) in

        arrays[type] = array

        if arrays.count == 2 {
            self.performSegue(withIdentifier:"JoinToAnswerPage",sender: arrays)
        }
    }

}

func getData(refe: String, completion: @escaping (([Any], String) -> ())) {
    var questionArray = [Any]()
    var answerArray = [Any]()
    let ref = Database.database().reference(fromURL: "https://pollapp-30419.firebaseio.com/").child("Questions/\(refe)/")
    ref.child("Question_And_Options").observeSingleEvent(of: .value,with: { snapshot in
        let enumerator = snapshot.children
        while let rest = enumerator.nextObject() as? DataSnapshot, let value = rest.value{
            questionArray.append(value)
        }
        completion(questionArray, "question")
    })
    ref.child("Answer_Key").observeSingleEvent(of: .value,with: { snapshot in
        let enumerator = snapshot.children
        while let rest = enumerator.nextObject() as? DataSnapshot, let value = rest.value{
            answerArray.append(value)
        }
        completion(answerArray, "answer")
    })
}

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    guard let joinViewController = segue.destination as? JoinAnswerViewController
        else {
            return
    }

    guard let arrays = sender as? [String : [Any]],
          let answers = arrays["answer"] as? [String],
          let questions = arrays["question"] as? [String]
        else { return }

    joinViewController.answers = answers
    joinViewController.options = questions
}

注意:当用户按下按钮时,他们应该立即得到响应。由于您是从网络加载数据,因此可能会有延迟,使用户怀疑是否发生了什么。最好将 JoinCodeTextField.text! 传递给 JoinAnswerViewController 并让它加载 question/answer 数据。 JoinAnswerViewController 可以在数据加载时显示 UIActivityIndicatorView(微调器),让用户知道数据即将到来。拥有两个数组后,您可以设置 JoinAnswerViewController.