首页 > 解决方案 > Swift如何在目标视图加载之前触发“为segue做准备”?

问题描述

我正在尝试从 firestore(google 数据库)加载数据并希望在 tableview 上显示。

所以在第一个 VC 中,通过准备函数,从数据库中获取数据,然后传输到第二个 VC(tableview)。但是有一个问题。我了解到准备函数在 viewdidload 之前,在我的应用程序中,准备函数在第二次 VC 加载之后。

这是我的代码。

第一风投

    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        let docRef = db.collection("Posting").getDocuments(){(querySnapshot, err) in
        if let err = err{
            print("errror getting documents")
        }else{
            for document in querySnapshot!.documents{
                print("\(document.documentID) => \(document.data())")
                self.savePostings.append(document.data())
            }
            print("\n\n\(self.savePostings)")
        }
        let vc = segue.destination as! PostingListTableViewController
        vc.updatedPostings = self.savePostings
        vc.testPrint = "잉 기모찌"
        print("배열 전달 확인\n\(vc.updatedPostings)\n\n\(self.savePostings)")
    }
    
}

第二个 VC (Tableview)

class PostingListTableViewController: UITableViewController {

//private var postings: Array<[String:Any]> = []
private var documents: [DocumentSnapshot] = []
var updatedPostings: Array<[String:Any]?> = []
var testPrint:String = ""

override func viewDidLoad() {
    super.viewDidLoad()
    print("view did load")
    // Uncomment the following line to preserve selection between presentations
    // self.clearsSelectionOnViewWillAppear = false

    // Uncomment the following line to display an Edit button in the navigation bar for this view controller.
    // self.navigationItem.rightBarButtonItem = self.editButtonItem
}

// MARK: - Table view data source



override func numberOfSections(in tableView: UITableView) -> Int {
    // #warning Incomplete implementation, return the number of sections
    return 1
}

override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    // #warning Incomplete implementation, return the number of rows
    return updatedPostings.count
}


override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "myTableCell", for: indexPath)
    cell.textLabel?.text = updatedPostings[indexPath.row]!["text"] as! String

    // Configure the cell...

    return cell
}

}

标签: iosswiftuitableviewuikitsegue

解决方案


正如@vadian 正确所说,您的问题是您正在进行异步调用。

prepare(for segue被调用 before viewDidLoad,但您在此之后的某个时间更新您的属性,当您的请求完成时,那是 after viewDidLoad

取而代之的是,我建议您执行以下操作:

  1. 删除你的 segue,将标识符添加到目标视图控制器

  2. 在里面tableView:didSelectRowAtIndexPath:运行你的getDocuments(或者IBAction如果这是一个按钮segue,在里面)

    2.1。您可以显示一些进度指示器,以便用户知道延迟的原因

  3. 完成后,使用instantiateViewControllerWithIdentifier从情节提要创建您的视图控制器并手动呈现。在这种情况下,您无需等待prepare(for segue设置您的属性。

如果您的 segue 从单元格调用,您可以将视图控制器添加为委托,如下所示:

那么您需要使您的视图控制器符合UITableViewDelegate,并且didSelectRowAt当用户按下单元格时将调用方法。您可以从indexPath.row

extension PostingListTableViewController: UITableViewDelegate {
    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        let docRef = db.collection("Posting").getDocuments(){(querySnapshot, err) in
            if let err = err{
                print("errror getting documents")
            }else{
                for document in querySnapshot!.documents{
                    print("\(document.documentID) => \(document.data())")
                    self.savePostings.append(document.data())
                }
                print("\n\n\(self.savePostings)")
            }
            // not sure if completion of getDocuments is called on main thread, if it does - you don't need this line
            DispatchQueue.main.async {
                let vc = storyboard!.instantiateViewController(identifier: "storyboard_identifier") as! PostingListTableViewController
                vc.updatedPostings = self.savePostings
                vc.testPrint = "잉 기모찌&quot;
                present(vc, animated: true)
                print("배열 전달 확인\n\(vc.updatedPostings)\n\n\(self.savePostings)")
            }
        }
    }
}

如果您是从普通按钮而不是单元格执行此转场,则可以使用@IBAction 执行相同操作:

@IBAction @objc func push() {
    let docRef = db.collection("Posting").getDocuments(){(querySnapshot, err) in
                if let err = err{
                    print("errror getting documents")
                }else{
                    for document in querySnapshot!.documents{
                        print("\(document.documentID) => \(document.data())")
                        self.savePostings.append(document.data())
                    }
                    print("\n\n\(self.savePostings)")
                }
                // not sure if completion of getDocuments is called on main thread, if it does - you don't need this line
                DispatchQueue.main.async {
                    let vc = storyboard!.instantiateViewController(identifier: "storyboard_identifier") as! PostingListTableViewController
                    vc.updatedPostings = self.savePostings
                    vc.testPrint = "잉 기모찌&quot;
                    present(vc, animated: true)
                    print("배열 전달 확인\n\(vc.updatedPostings)\n\n\(self.savePostings)")
                }
            }
}

推荐阅读