没有DispatchQueue.main.async的意外布局行为

时间:2018-05-28 10:41:49

标签: ios swift multithreading user-interface grand-central-dispatch

有时当自动布局或UI更改没有按照我的意愿执行时,我将代码包装到DispatchQueue.main.async中并且它得到解决(例如):

override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
    super.viewWillTransition(to: size, with: coordinator)
    DispatchQueue.main.async {
        self.tableview.reloadData()
    }
}

但是在没有Thread.current的情况下使用(DispatchQueue)调试此代码会告诉我已经在主线程中,但它不能很好地完成动画,只需添加{{1} } 工作良好。我想知道DispatchQueue.main.async究竟是什么让它起作用。因为我认为它只是让代码在主线程中执行,但是如果它已经在主线程中执行它不应该做任何事情......但是这样它工作正常而没有创建布局问题。

(我遇到过不同的代码和不同的应用程序,我总是调试并告诉我已经在主线程中了。)

我认为这可能是因为dispatchQueue产生了一点延迟,但是在更多不需要延迟的地方发生了这种情况(Swift Animate duration not working in CGAffineTransform - >今天我调试了这个问题而没有dispatchMainQueue和它也会在主线程中执行,但如果没有调度则无法正常工作)

1 个答案:

答案 0 :(得分:3)

简单地说,当您使用DispatchQueue.main.async时,将在一小段延迟后调用self.tableview.reloadData()(因为块将在下一个循环中执行)。这就是你有所不同的原因。

在这种情况下,当设备旋转时执行viewWillTransition(to:with:)。这意味着此时可能出现错误,设备尚未旋转。因此,如果您致电self.tableview.reloadData(),可能会产生错误的结果。

为什么DispatchQueue.main.async可以解决问题? - 这是因为DispatchQueue.main.async在执行块之前给出了延迟,并且在此延迟后,self.tableview.reloadData()将在设备之后调用完成旋转。这就是它给出正确结果的原因

使用animate(alongsideTransition:completion:)执行此操作,您无需使用DispatchQueue.main.async

override func willTransition(to newCollection: UITraitCollection, with coordinator: UIViewControllerTransitionCoordinator) {
  coordinator.animate(alongsideTransition: nil, completion: { (_) in
    self.tableview.beginUpdates()
    self.tableview.endUpdates()
  })
}