因此,我开始学习Grand Central Dispatch的基础知识以及iOS应用程序的多线程概念。每个教程都会告诉您必须在主线程上运行UI事件,但我不完全理解为什么。
这是我昨天遇到的一个问题,最后通过在主线程上运行segue来修复它,但我仍然不明白为什么从主线程运行它是一个问题:
我有一个自定义初始VC(条形码扫描仪)和一个附加UIWebView
的新视图控制器的segue。一旦VC找到条形码,它就会调用一个处理程序,在那个闭包中,我有一个performSegueWithIdentifier
。但是,由于这个原因,我得到了EXC_BAD_ACCESS
(当第二个VC有标签或UIImageView
时,它没有发生,只有UIWebView
)。我终于意识到由于某种原因,闭包被称为主线程,因此segue正在主线程上执行。为什么要在另一个线程上执行segue会引发内存错误?是因为self
中的self.performSegueWithIdentifier
某种程度上是零吗?为什么Swift不会自动在主线程上发送一个segue事件?
答案 0 :(得分:6)
有趣的问题!崩溃与UIKit无关。这是特定于UIWebView的崩溃。查看堆栈跟踪,异常发生在WebCore::FloatingPointEnvironment::saveMainThreadEnvironment
函数中,该函数是WebKit init进程的一部分。由于WebKit管理自己的线程执行环境,因此需要一个明确的起点(即主线程)来构建这个环境。
在main
以外的线程上执行的UIKit操作(如呈现视图控制器)不会导致异常,但它们会被延迟(取决于调度队列的QoS)。
至于为什么UIKit操作没有在主队列上自动分派,我只能推测在库调用中添加额外的检查会增加太多的冗余工作,只需按照惯例就可以避免。
有关UIKit和主线程的更多讨论,请参阅以下答案:Why must UIKit operations be performed on the main thread?
简短的回答是,修改应用UI的所有操作都需要在一个地方聚集在一起进行评估,以定期生成下一帧(具体为V-Sync间隔)。跟踪所有变异状态需要所有更改同步发生,并且出于性能原因,所有这些操作通常都是按帧进行批处理并执行一次(同时还与GPU协调)。
答案 1 :(得分:2)
使线程安全很困难,并且具有重要的性能影响,所有这些都可以通过要求访问来自单个(主)线程来避免。您希望UI框架尽可能快(即响应)。如果您声明所有UI对象都只是主线程,那么您不必通过一堆同步开销来降低它们的速度。我听说过它,“如果UIKit只是主线程,那么为什么他们不检查当前线程,abort()
如果它不是主线程线程&#39?;并且答案是相同的:即使是这样的简单检查,由于需要检查的方法的数量以及它们被调用的频率,也会导致明显的性能损失。这完全取决于速度。
另外,请记住,不久前,所有应用程序都是单线程的。