首页 > 解决方案 > 没有 DispatchQueue.main.async 的意外布局行为

问题描述

有时,当自动布局或 UI 更改没有按照我的意愿执行时,我将代码包装到 a 中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它告诉我它已经在主线程中,但它不能很好地完成动画,只是添加DispatchQueue.main.async工作正常。我想知道究竟是什么DispatchQueue.main.async使它起作用。因为我认为它只是让代码在主线程中执行,但如果它已经在主线程中执行,它不应该做任何事情......但是这样它工作正常并且不会产生布局问题。

(不同的代码和不同的应用程序发生在我身上,我一直在调试并告诉我已经在主线程中)。

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

标签: iosswiftmultithreadinguser-interfacegrand-central-dispatch

解决方案


简单地说,当您使用DispatchQueue.main.async,时self.tableview.reloadData()会在一小段延迟后被调用(因为 block 将在下一个循环中执行)。这就是为什么你有差异。

在这种情况下,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()
  })
}

推荐阅读