等待函数首先执行,然后再移动到下一行代码

Posted

技术标签:

【中文标题】等待函数首先执行,然后再移动到下一行代码【英文标题】:Wait for function to execute first before moving to next line of code 【发布时间】:2017-07-09 16:08:03 【问题描述】:

我在我的应用程序中使用 CloudKit,但在表格视图中显示数据时遇到问题。在viewDidLoad(),我正在从 CloudKit 数据库中获取数据。

然后在表格视图函数中,我对行数执行 CKRecord 对象计数。

但是 count 返回 0 到表视图,几秒钟后返回行数。因为这个表格视图没有显示结果。

override func viewDidLoad() 
    super.viewDidLoad()
    loadNewData()


func loadNewData() 
    self.loadData = [CKRecord]()
    let publicData = CKContainer.default().publicCloudDatabase
    let qry = CKQuery(recordType: "Transactions", predicate: NSPredicate(format: "TRUEPREDICATE", argumentArray: nil))
    qry.sortDescriptors = [NSSortDescriptor(key: "Transaction_ID", ascending: true)]
    publicData.perform(qry, inZoneWith: nil)  (results, error) in
        if let rcds = results 
            self.loadData = rcds
        
        if error != nil 
            self.showAlert(msg: (error?.localizedDescription)!)
        
    


func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int 
    return loadData.count


func numberOfSections(in tableView: UITableView) -> Int 
    return 1


func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell 
    let cell = tableView.dequeueReusableCell(withIdentifier: "Cell2", for: indexPath) as! ViewAllTransactionsTVCell

    let pn = loadData[indexPath.row].value(forKey: "Party_Name") as! String
    let amt = loadData[indexPath.row].value(forKey: "Amount") as! String
    let nrt = loadData[indexPath.row].value(forKey: "Narattions") as! String 
    let dt = loadData[indexPath.row].value(forKey: "Trans_Date") as! String


    cell.partyNameLabel.text = pn
    cell.dateLabel.text = dt
    cell.narationLabel.text = nrt
    cell.amountLabel.text = amt

    return cell

【问题讨论】:

在回答您的问题时,不要“等待”。只需在publicData.perform 完成处理程序中调用self.tableView.reloadData()。如果你试图等待,你可能会引入各种微妙的问题。顺便说一句,如果您对否决票感到疑惑,那无疑是因为这个问题已经在 Stack Overflow 上被问和回答了数百次。只需搜索“[ios] wait for function”,或者更严格地说,“[ios] cloudkit wait”。 【参考方案1】:

您不应该等待,而是在调用 perform 完成处理程序时触发数据的重新加载:

publicData.perform(qry, inZoneWith: nil)  (results, error) in
    if let rcds = results 
        DispatchQueue.main.async 
            self.loadData = rcds
            self.tableView.reloadData()
        
    
    if error != nil 
        self.showAlert(msg: (error?.localizedDescription)!)
    

请注意,我将重新加载进程分派到主队列,因为您不能保证在主线程上运行此进程。正如the documentation 所说:

您的块必须能够在应用程序的任何线程上运行...

而且因为 UI 更新必须在主线程上进行(并且因为您希望同步您对 loadData 的访问),所以只需将其分派到主队列,就像上面一样。

【讨论】:

嗨。谢谢您的回复。最后它调用 tableview 函数。但现在我收到“致命错误:在展开可选值时意外发现 nil”错误。尝试了一切,但没有运气 好吧,您必须确定是哪一行导致了该错误,不是吗。不过,一个可能的候选人是loadData。你是怎么定义的?如果它是可选的,你的numberOfRowsInSection 应该返回loadData?.count ?? 0(即如果可以的话,安全地打开它,否则返回零)。如果这不是您得到“在展开 Optional 时找到 nil”的地方,请告诉我们哪一行正在生成该错误。 错误来自 tableView(...cell for row ) fn line 2nd 我使用了 "let pn = loadData[indexPath.row].value(forKey: "Party_Name") as! String " 并且可能其他行会导致这种情况,因为它会因错误而停在那里 @Aakash 那么,问题出在您从 CloudKit 成功返回数据之后?好的,那么loadData 实际上包含什么?也许您的键名不正确。您需要进行一些诊断以找出问题所在。 'loadData' 返回我认为的正确值,因为它返回实际的行数。对于键 - Party_Name 是 String,Trans_Date 是 String,Amount 是 Double,Narattions 是 String,我不知道是什么导致了错误。

以上是关于等待函数首先执行,然后再移动到下一行代码的主要内容,如果未能解决你的问题,请参考以下文章

如何调用异步函数

如何在移动到下一行代码之前完成 NSURLSession 请求

puppeteer:在继续下一行之前等待 N 秒

在java一个方法中,如何让一行代码执行完毕以后等待几秒钟后再执行另一行代码 主要 是一个方法中

为啥 JavaScript 需要“等待”? [复制]

在执行下一行代码之前等待超时完成