为什么必须在主线程上执行UIKit操作?

时间:2013-08-27 13:39:01

标签: iphone ios multithreading uikit posix

我试图理解为什么无法使用多个线程执行UI操作。这也是OpenGL或cocos2d等其他框架中的要求吗?

C#和javascript等其他语言怎么样?我尝试在google中查找,但人们提到了一些我不理解的POSIX线程。

5 个答案:

答案 0 :(得分:16)

在Cocoa Touch中,UIApplication即应用程序的实例附加到主线程,因为此线程由Cocoa Touch的入口点函数UIApplicatioMain()创建。它设置主事件循环,包括应用程序的运行循环,并开始处理事件。应用程序的主事件循环接收所有UI事件,即触摸,手势等。

来自文档UIApplicationMain()

  

此函数从主体类实例化应用程序对象,并从给定的类中实例化委托(如果有)并设置应用程序的委托。它还设置主事件循环,包括应用程序的运行循环,并开始处理事件。如果应用程序的Info.plist文件指定要加载的主nib文件,通过包含NSMainNibFile键和值的有效nib文件名,此函数将加载该nib文件。

这些应用程序UI事件会进一步转发到UIResponder的响应者链,通常类似于UIApplication - > UIWindow - > UIViewController - > { {1}} - >子视图(UIView,等)

响应者处理按钮按下,点击,捏缩放,滑动等事件,这些事件会在UI中转换为更改。因此,您可以看到这些事件链发生在主线程上,这就是为什么UIButton,包含响应者的框架应该在主线程上运行。

再次从文档UIKit

  

在大多数情况下,UIKit类只能从应用程序的主线程中使用。对于从UIResponder派生的类或者涉及以任何方式操纵应用程序的用户界面的类,尤其如此。

修改

为什么drawRect需要在主线程上?

<{>} UIKitdrawRect:作为UIKit生命周期的一部分调用。所以UIView绑定到主线程。以这种方式绘图是昂贵的,因为它是使用主线程上的CPU完成的。通过使用CALayer技术(核心动画)提供硬件加速图形。

另一方面,

drawRect:充当视图的后备存储。然后,视图将显示其当前状态的缓存位图。对视图属性的任何更改都将导致后备存储中的更改由GPU在备份副本上执行。但是,视图仍需要提供初始内容并定期更新视图。我还没有真正使用OpenGL,但我认为它也使用了图层(我可能错了)。

据我所知,我试图回答这个问题。希望有所帮助!

答案 1 :(得分:4)

来自:https://www.objc.io/issues/2-concurrency/thread-safe-class-design/

  

Apple的一个有意识的设计决定是没有UIKit是线程安全的。使其具有线程安全性并不会对性能产生太大影响;事实上它会让很多东西变慢。 UIKit与主线程绑定的事实使得编写并发程序和使用UIKit变得非常容易。您所要做的就是确保始终在主线程上调用UIKit。

因此,根据这一点,必须在主线程上访问UIKit对象这一事实是苹果公司决定支持性能的。

答案 2 :(得分:1)

C#的行为相同(参见例如:Keep the UI thread responsive)。 UI更新必须在UI线程中完成 - 大多数其他事情应该在可能的后台完成。

如果不是这种情况,那么必须在UI中完成所有更新之间的同步地狱......

答案 3 :(得分:0)

每个系统,每个库,都需要关注线程安全,并且必须做一些事情来确保线程安全,同时还要关注正确性和性能。

在iOS和MacOS X用户界面的情况下,决定通过仅允许在主线程上调用和执行UI方法来使UI线程安全。就是这样。

由于存在许多复杂的事情,至少需要序列化以防止发生混乱,我在后台线程上允许UI时看不到很多。

答案 4 :(得分:-1)

因为您希望用户能够在UI发生变化时看到它们。如果您能够在后台线程中执行UI更改并在完成时显示它们,那么应用程序似乎表现不正常。

所有非UI操作(或至少是非常昂贵的操作,如下载内容或进行数据库查询)应该在后台线程上进行,而所有UI更改必须始终在提供尽可能顺畅的用户体验的主要线索。

我不知道在Windows Phone应用程序的C#中它是什么样的,但我希望它是相同的。在Android上,系统甚至不允许你在主线程上进行下载,直接创建后台线程。

根据经验 - 当你想到主线程时,请考虑“用户看到的内容”。