Dispatch.main.async如何"update the UI"?
How does Dispatch.main.async "update the UI"?
我已经使用 Swift 一段时间了,GCD 仍然让我有些困惑。
我读过:
https://www.raywenderlich.com/60749/grand-central-dispatch-in-depth-part-1
以及派送时的 Apple 文档:
https://developer.apple.com/documentation/dispatch
我理解 GCD 允许多个任务 运行 在不同线程上的总体概念(我认为是正确的)。
我不太明白的是Dispatch.main.async
"updates the UI"。
例如,如果我在某处调用 api 并且数据被 returned - 假设 return 所有数据需要 5 秒,那么如何使用 Dispatch.main.async
帮助更新 UI? Dispatch.main.async
如何知道要更新什么 UI?
而且我仍然不太明白 GCD 的位置,为什么不能使用某种观察者或委托或闭包来调用所有数据加载时的位置?
并且回复:如果我正在进行 api 调用但不立即使用数据,则使用 GCD "updating the UI" 例如。只是将数据存储在一个数组中,直到我决定使用它,然后才需要使用 Dispatch.main.async
?
我使用 firebase/firestore 作为数据库已有一段时间了。 Firebase 有自己的监听器和异步的 运行s。关于 iOS/Swift 中从 firebase 处理异步 return 的最佳方法,我仍然无法得到很好的答案。例如,当我的应用程序加载时,如果我去 firebase 获取数据以填充 tableviewcontroller,什么是了解所有数据何时已 returned 的最佳方法?我一直在为此使用委托,但想知道是否以及如何使用 Dispatch.main.async
。
Dispatch.main.async
不会 更新 UI。故事走向了一个不同的方向:如果你想 更新 UI,你必须从 main 线程进行。如果你当前的代码不是 运行ning 在主线程上,Dispatch.main.async
是在 main[=41= 上有一些代码 运行 的最方便的方法] 线程。
这是一个影响大多数操作系统的旧限制:UI 相关操作,例如更改 UI 中的元素,只能从特定线程调用,通常是所谓的 main线程。
在许多情况下,这不是问题,因为您的 UI 相关代码通常在某些 UI 事件(用户点击或点击、按键等)触发时起作用。这些事件回调发生在主线程上。所以不存在线程问题。
使用 GCD,您可以 运行 长时间 运行 单独线程上的任务,这样任务就不会减慢甚至阻塞 UI。所以当这些任务完成并且你想更新 UI (例如显示结果)时,你必须在主线程上这样做。使用 Dispatch.main.async
你可以要求 GCD 运行 主线程上的一段代码。 GCD 不知道 UI。您的代码必须知道要更新什么。 GCD 只是 运行 将您的代码放在所需的线程上。
如果在您的任务结束时 UI 中没有任何内容可显示或以其他方式更新,那么您不需要调用 Dispatch.main.async
.
更新 Firebase
Firebase 数据库客户端在单独的后台线程中执行所有网络和磁盘操作关闭 主线程。
Firebase 数据库客户端会在主线程 上调用您的代码的所有回调。
因此无需在 Firebase 回调中调用 Dispatch.main.async
。你已经在主线程了。
仅供参考,所有 UI 代码都需要在主线程上运行的原因是因为绘图是一个(相对于 CPU 时间)漫长而昂贵的过程,涉及许多数据结构和数百万像素。图形代码在进行帧更新时本质上需要锁定所有 UI 资源的副本,因此您不能在绘制过程中编辑这些资源,否则如果您去更改内容就会出现奇怪的伪像系统渲染这些对象时进行到一半。由于所有绘图代码都在主线程上,这让系统阻塞主线程直到渲染完成,所以 none 的更改会得到处理,直到当前帧完成。此外,由于某些绘图被缓存(基本上呈现为纹理,直到您调用 setNeedsDisplay 或 setNeedsLayout 之类的东西),如果您尝试从后台线程更新某些内容,它完全有可能不会显示并导致状态不一致,这就是为什么您不应该在后台线程上调用任何 UI 代码的原因。
我已经使用 Swift 一段时间了,GCD 仍然让我有些困惑。
我读过:
https://www.raywenderlich.com/60749/grand-central-dispatch-in-depth-part-1
以及派送时的 Apple 文档:
https://developer.apple.com/documentation/dispatch
我理解 GCD 允许多个任务 运行 在不同线程上的总体概念(我认为是正确的)。
我不太明白的是Dispatch.main.async
"updates the UI"。
例如,如果我在某处调用 api 并且数据被 returned - 假设 return 所有数据需要 5 秒,那么如何使用 Dispatch.main.async
帮助更新 UI? Dispatch.main.async
如何知道要更新什么 UI?
而且我仍然不太明白 GCD 的位置,为什么不能使用某种观察者或委托或闭包来调用所有数据加载时的位置?
并且回复:如果我正在进行 api 调用但不立即使用数据,则使用 GCD "updating the UI" 例如。只是将数据存储在一个数组中,直到我决定使用它,然后才需要使用 Dispatch.main.async
?
我使用 firebase/firestore 作为数据库已有一段时间了。 Firebase 有自己的监听器和异步的 运行s。关于 iOS/Swift 中从 firebase 处理异步 return 的最佳方法,我仍然无法得到很好的答案。例如,当我的应用程序加载时,如果我去 firebase 获取数据以填充 tableviewcontroller,什么是了解所有数据何时已 returned 的最佳方法?我一直在为此使用委托,但想知道是否以及如何使用 Dispatch.main.async
。
Dispatch.main.async
不会 更新 UI。故事走向了一个不同的方向:如果你想 更新 UI,你必须从 main 线程进行。如果你当前的代码不是 运行ning 在主线程上,Dispatch.main.async
是在 main[=41= 上有一些代码 运行 的最方便的方法] 线程。
这是一个影响大多数操作系统的旧限制:UI 相关操作,例如更改 UI 中的元素,只能从特定线程调用,通常是所谓的 main线程。
在许多情况下,这不是问题,因为您的 UI 相关代码通常在某些 UI 事件(用户点击或点击、按键等)触发时起作用。这些事件回调发生在主线程上。所以不存在线程问题。
使用 GCD,您可以 运行 长时间 运行 单独线程上的任务,这样任务就不会减慢甚至阻塞 UI。所以当这些任务完成并且你想更新 UI (例如显示结果)时,你必须在主线程上这样做。使用 Dispatch.main.async
你可以要求 GCD 运行 主线程上的一段代码。 GCD 不知道 UI。您的代码必须知道要更新什么。 GCD 只是 运行 将您的代码放在所需的线程上。
如果在您的任务结束时 UI 中没有任何内容可显示或以其他方式更新,那么您不需要调用 Dispatch.main.async
.
更新 Firebase
Firebase 数据库客户端在单独的后台线程中执行所有网络和磁盘操作关闭 主线程。
Firebase 数据库客户端会在主线程 上调用您的代码的所有回调。
因此无需在 Firebase 回调中调用 Dispatch.main.async
。你已经在主线程了。
仅供参考,所有 UI 代码都需要在主线程上运行的原因是因为绘图是一个(相对于 CPU 时间)漫长而昂贵的过程,涉及许多数据结构和数百万像素。图形代码在进行帧更新时本质上需要锁定所有 UI 资源的副本,因此您不能在绘制过程中编辑这些资源,否则如果您去更改内容就会出现奇怪的伪像系统渲染这些对象时进行到一半。由于所有绘图代码都在主线程上,这让系统阻塞主线程直到渲染完成,所以 none 的更改会得到处理,直到当前帧完成。此外,由于某些绘图被缓存(基本上呈现为纹理,直到您调用 setNeedsDisplay 或 setNeedsLayout 之类的东西),如果您尝试从后台线程更新某些内容,它完全有可能不会显示并导致状态不一致,这就是为什么您不应该在后台线程上调用任何 UI 代码的原因。