【问题标题】:How to properly use DispatchQueue.main.async?如何正确使用 DispatchQueue.main.async?
【发布时间】:2021-01-15 11:49:08
【问题描述】:

我的应用中有一个循环,可能需要几秒钟才能处理完。

我希望在循环在后台运行时立即关闭屏幕。

这可能吗?

我试过只添加循环:


DispatchQueue.main.async {
                for _ in 1...self.numberOfTransactionsToAdd {
                    
                    let newTransaction = Transaction()
                    
                    var timeAdded = 1.months
                    newTransaction.transactionAmount = self.amountTextField.text!.toDouble()
                    newTransaction.transactionDescription = self.descriptionTextField.text
                    newTransaction.transactionDate = self.datePicked
                    newTransaction.transactionCategory = self.categoryPicked
                    newTransaction.repeatInterval = self.repeatInterval
                    newTransaction.transactionSubCategory = self.subcategoryPicked
                    newTransaction.subCategoryName = self.subcategoryPicked!.subCategoryName
                    
                  
                    try! self.realm.write {
                        self.realm.add(newTransaction)
                    }
                    
                    self.datePicked = self.datePicked + timeAdded
                }
            }
                
            }

我已经尝试添加整个函数:

    @IBAction func doneButtonPressed(_ sender: UIButton) {
        
        self.dismiss(animated: true, completion: nil)

        DispatchQueue.main.async {

            self.saveTransaction()

        }
        
    }

但在视图关闭之前屏幕仍然挂起。

这是我第一次使用 DispatchQueue。我已经阅读了 Apple 关于它的文档,但它非常模糊。

这甚至是正确的方法吗?

有人可以帮助指导新手找到正确的方法吗?

【问题讨论】:

  • 为什么有两个DispatchQueues?第一段代码是否显示saveTransaction
  • 那些代码 sn-ps 只是我尝试过的两种不同的东西,而不是一起尝试。

标签: swift for-loop asynchronous dispatch-queue


【解决方案1】:

问题是非ui工作(后台工作)对主队列本身的异步调用。 将DispatchQueue.main.async 替换为DispatchQueue.global().async。原因是所有非 UI 任务都应该在主队列之外异步运行。

完成上述修复后,您仍然会遇到另一个问题,即从非主队列访问 UI 元素(因为现在我们的代码将在全局队列上运行)。原因是您将从全局队列中获取 UI 元素数据(如 amountTextField 的文本等)。将 UI 的数据存储在局部变量中,并在循环代码中使用局部变量,而不是调用 amountTextField 和其他文本字段。

var amountData: Double
var description: String

@IBAction func doneButtonPressed(_ sender: UIButton) {
    amountData = amountTextField.text!.toDouble()
    descriptionTextField = descriptionTextField.text
    DispatchQueue.global().async {
        self.saveTransaction()
    }
    self.dismiss(animated: true, completion: nil)
}

func saveTransaction() {
    for _ in 1...self.numberOfTransactionsToAdd {
        .
        .
        newTransaction.transactionAmount = self.amountData
        newTransaction.transactionDescription = self.descriptionTextField
        .
        .
        .
    }
    
}

【讨论】:

    【解决方案2】:

    您的问题似乎与 GCD 有关:

    @IBAction func doneButtonPressed(_ sender: UIButton) {
        DispatchQueue.global(qos: .background).async {
    //  do here your loading, fetching the data etc
            self.saveTransaction()
        DispatchQueue.main.async {
    //  do here ui works, because user doesn't want to wait for touching etc so it has to be asp
            self.dismiss(animated: true, completion: nil)
        }
      }
    }
    

    【讨论】:

    • 当我尝试这个时,我得到“由于未捕获的异常'RLMException'而终止应用程序,原因:'从不正确的线程访问的领域。”
    • 我没有不尊重的意思,非常感谢您的帮助。我会调查这个问题并保持此页面更新。
    猜你喜欢
    • 1970-01-01
    • 2019-03-30
    • 1970-01-01
    • 2020-10-17
    • 2017-11-01
    • 2020-12-04
    • 2012-07-12
    • 2013-01-21
    • 2021-10-24
    相关资源
    最近更新 更多