检测主线程外的 UI 操作

Posted

技术标签:

【中文标题】检测主线程外的 UI 操作【英文标题】:Detect UI actions outside of main thread 【发布时间】:2013-04-09 19:52:10 【问题描述】:

注意:此问题与Warn on calls to UIKit from background threads 有关,但未对以下两种方法给出答案。

我遇到了应用程序屏幕快速闪烁的问题。我过去已经遇到过这个问题,这是由于在主线程之外更新了 UI 元素。

因此我在很多地方都放了以下代码:

assertMainThread();

这是:

#define assertMainThread() NSAssert([NSThread isMainThread],@"Method called using a thread other than main!")

当然,我不能用 assertMainThread() 覆盖整个代码,因为有很多地方,而且有些代码被后台 GCD 队列以合法的方式使用。

我查看了很多地方,但找不到让 XCode 或 LLDB 告诉我 UI 元素何时在主线程之外更新的方法。我认为可以使用符号断点或其他一些机制来中断例如在主线程之外调用 UIKit 中的常用方法但找不到方法的地方。

我还认为 UIKit 可以在进行此类调用时在运行时发出警告?或者至少给我们一些工具来帮助调试此类问题。

我查看(但未尝试)的另一种方法是使用一些代码覆盖技术并尝试从视觉上提取在代码中的哪个点运行的线程,但没有走那条路线。

您对如何解决这个问题有任何想法吗?

【问题讨论】:

我发现这很有趣并对其进行了调查:***.com/questions/10424979/… 此代码(只需添加到项目并在没有 ARC 的情况下编译此文件)会导致 UIKit 访问主线程之外的断言:gist.github.com/steipete/5664345 我刚刚使用它来处理许多 UIKit/主线程问题我刚刚继承的一些代码。 【参考方案1】:

Xcode 9 及更高版本

Xcode 9 引入了一个Main thread checker,它可以嗅探许多可能在主线程外执行的相关问题。您可以在您的方案选项中以通常的方式启用此分析器以及其他运行时分析器。

Xcode 8.3 及更早版本

基于 steipete 要点的替代 Xcode 方式解决方案 - 符号断点:

您可以轻松地为任何UIKit 类上的一些其他方法添加断点,例如-[UIView setNeedsDisplay] 等。

【讨论】:

这非常有用!发送! 在 Xcode 9 中,没有办法设置一个断点来捕获所有内容吗? 不,断点在源文件中的任一代码行或要检查的符号调用上都“适用”的意义上是通用的。然而,如前所述,Xcode 9 中有一个完整的消毒剂,它检查 Apple 工程师定义的AppKit/UIKit 特定问题。 帮我修复了产品中的一个错误,谢谢【参考方案2】:

从 Xcode 9 开始,Apple 在 Xcode 中集成了一个 Main Thread Checker,如果您使用 Xcode 调试器运行您的应用程序,默认情况下会启用它。

可以在诊断选项卡下的方案配置中禁用/启用。

【讨论】:

【参考方案3】:

@Michi 答案的 Xcode 11/Swift 版本

【讨论】:

以上是关于检测主线程外的 UI 操作的主要内容,如果未能解决你的问题,请参考以下文章

Java子线程中操作主线程Private级别数据

Android 中handler消息机制的理解

android AsyncTask的方法在哪几个线程中调用

Android 中handler消息机制的理解

Java 多线程安全机制

volatile-验证线程之间的可见性