17

我们可以有许多处理程序:触摸处理程序、UIControl 处理程序(按钮、滑块)、performSelector、CADisplayLink、NSTimer 事件、手势识别器、加速度计处理程序和UIView 动画完成块,以及其他一些。

他们都在同一个线程中吗?也就是只能同时运行其中一个?

其他一些方法或处理程序是否可以成为另一个线程的一部分,因此可以创建竞争条件?

4

1 回答 1

16

通常,您会发现 iOS 上的大多数简单应用程序都倾向于在主线程上执行几乎所有操作。正如您所指出的,在您将多线程引入图片的那一刻,您添加了另一组需要注意的棘手问题。许多开发人员不想为这种增加的复杂性而烦恼,或者不熟悉 GCD 或一般的线程,因此他们避免在后台线程或 GCD 队列上做任何事情。

您在问题中列出的几个项目涉及与 UIKit 的交互,通常这些交互必须发生在主线程上(不过,iOS 4.x 添加了在后台执行一些绘图功能的能力)。您在主线程上收到触摸和其他相关事件。如果您希望更新界面的大多数方面,那么安全的方法是在主线程上执行这些更新。

计时器(NSTimer、CADisplayLink)可以通过将它们附加到在该后台线程上运行的 NSRunLoop 来在后台线程上触发它们的更新。你很少看到人们这样做,但它可以做到。通常,人们在主运行循环上配置计时器,这会导致回调在主线程上传递。

执行动画时,动画本身将在后台线程上运行(您会看到,当您用其他东西阻塞主线程时它们不会停止),但您几乎总是会在主线程上收到完成块或回调完成后线程。如果我没记错的话,会有一两个例外,它们在 Apple 的文档中都有说明。在与可能没有意识到幕后发生的事情的开发人员打交道时,在主线程上触发这些回调是一种安全的方法。

综上所述,有很好的理由要为您的应用程序添加多线程。因为所有用户界面更新和触摸交互都发生在主线程上,如果你有一些计算量很大的东西或者只是需要很多时间来执行,如果你在你的主线程上运行它,你似乎已经冻结了你的应用。这是一种糟糕的用户体验,因此您希望将此任务移至后台线程,以便用户可以在此过程中继续与您的应用程序交互。此外,越来越多的 iOS 设备每天都在出货,其中包含多个内核,并且在这些内核之间平衡您的工作负载并高效使用此硬件需要一定程度的并发处理。

人们已经写过有关编写多线程代码时的最佳实践的书籍,您可以在这里找到很多关于此的问题,因此我不会过多详细说明。我可以告诉你的是,你应该阅读 Apple 的并发编程指南并观看过去两年处理 Grand Central Dispatch 的 WWDC 视频。借助 GCD,Apple 以高效且(相对)安全的方式将多线程添加到您的应用程序变得更加容易,我鼓励您为自己的应用程序研究这一点。

例如,我有一个开源 iOS 应用程序,它可以执行分子结构的详细渲染。我在后台 GCD 队列上渲染每一帧,因为有时它们需要超过 1/60 秒的时间来处理,在这些情况下,如果这一切都在主线程上,它们会导致触摸事件被丢弃并且界面卡顿. 此外,当在较新的多核设备上运行时,我已经看到了高达 40% 的性能提升。为了避免竞争条件,我将与共享数据结构和上下文的交互包装在串行调度队列中,这样无论特定块在哪个线程上运行,一次只能有一个操作使用资源。这只需要添加几行代码,但性能和用户体验的好处是巨大的。

于 2012-06-08T18:10:23.813 回答