我试图理解为什么无法使用多个线程执行UI操作。这也是OpenGL或cocos2d等其他框架中的要求吗?
C#和javascript等其他语言怎么样?我尝试在google中查找,但人们提到了一些我不理解的POSIX线程。
答案 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需要在主线程上?
<{>}UIKit
由drawRect:
作为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上,系统甚至不允许你在主线程上进行下载,直接创建后台线程。
根据经验 - 当你想到主线程时,请考虑“用户看到的内容”。