试图了解 iOS 中后台线程行为的幕后情况

Posted

技术标签:

【中文标题】试图了解 iOS 中后台线程行为的幕后情况【英文标题】:Trying to understand what's going on behind the scenes of background thread behavior in iOS 【发布时间】:2019-09-10 22:53:15 【问题描述】:

我知道 UI 需要在主线程上更新。

我只是想了解幕后发生的事情,导致尝试从后台线程更新 UI 的代码出现难以置信的长时间延迟。

假设您的应用在数据库调用方面的初始设置已完成,并且您的 UITableView 数据源数组已完全填充。所有视图控制器及其子视图都已完全渲染。您的代码除了等待用户操作之外什么都不做。为了更好地衡量,您等待的时间比您认为需要的多 30 秒以确保这一点。

然后您执行一些用户操作,触发一行代码尝试在后台线程上更新 UI。结果是在 UI 更新之前整整 2 或 3 秒延迟。

如果一个后台线程相当于一个额外的处理器与一个主处理器并行运行,并且如果那个额外的处理器正好有零个其他代码要运行,那么它到底在做什么整整两秒,这是一个永恒的执行一行代码?

【问题讨论】:

你是对的,我会编辑我的问题。我得出了这个错误的结论,因为当您从 didSelectRowAt() 呈现视图控制器时,Apple 的代码中有一个错误,而该错误的解决方法是将该视图控制器的表示包装在 DispatchQueue.main.async 中。见:***.com/questions/21075540/… 我不相信那个“错误”。 一个更有用的评论是解释你为什么不相信它。 因为我在我编写的每个应用程序中都使用didSelect 十年了,而且我从未遇到过问题? 【参考方案1】:

您已经创建了一个竞争条件。系统没有做任何事情;它不知道它需要更新显示。作为发生的竞争条件的示例,您可以很容易地得到这样的情况:

(主)UI 事件发生 (main) 设置“需要显示” (main)Runloop 循环并看到“需要显示” (main) Runloop 开始显示更新 (main) 对所有需要更新的内容进行快照并开始处理它们。 (背景)导致设置“需要显示”的一些事件 (主)完成列表(不包括那个背景) (main) 清除“需要显示”(它不是堆栈;它只是一个布尔值,现在它是“假”) (main) Runloop 循环运行,发现不需要显示任何内容。 (背景东西丢了) ... ... 2 秒,或其他任何时间。可能需要很长时间,或者马上。 ... (主要)发生了设置“需要显示”的事情 (主要)现在背景中发生的事情被绘制(如果你幸运的话)

这可能是该问题最温和的版本。 UIKit 不是线程安全的。在后台进行随机更改绝对会破坏状态并导致各种奇怪的行为和崩溃。如果幸运的话,您的更新将需要一段时间才能显示出来。

【讨论】:

以上是关于试图了解 iOS 中后台线程行为的幕后情况的主要内容,如果未能解决你的问题,请参考以下文章

HotspotJVM后台运行的系统线程

iOS 在后台保存主线程 NSManagedObjectContext 更改

从后台线程奇怪的行为更新 datagridview

如何在 iOS 的后台线程中运行 XMPP Room Join & Invite 进程

如何在不知道当前/主视图是啥的情况下从后台线程打开新视图?

总是在后台运行线程/进程?