我有一些很重的代码,运行时间大约为0.2秒。
我这样设置活动指示器;然而,它并没有显示出来,而是整个屏幕冻结了大约0.2秒,直到代码完成。
func heavyWork() {
self.actvityIndicator.startAnimating()
...
// heavy loop codes here
...
self.activityIndicator.stopAnimating()
}
这是使用活动指示器的正确方法吗?
当我评论出来
// self.activityIndicator.stopAnimating()
活动指示器显示并停留在那里-代码设置正确。
但是UI似乎没有在正确的时间更新。
正如我所说,屏幕只是冻结而不显示活动指示器,直到繁重的代码完成。
4条答案
按热度按时间dphi5xsq1#
也许你想继续这样的模式:
因为繁重的工作应该发生在一个 * 后台 * 线程,你需要在一个 * 主 * 线程后更新UI。
func heavyWork()
;如果没有,你可能需要将最初的UI更新转移到主线程。jbose2ul2#
如果你想让应用程序在执行一些繁重的任务时响应,你需要在后台线程上执行它。
这大概是这里发生的事情:应用的主线程在run循环中执行。在每次循环迭代开始时,iOS检查任何事件(例如用户交互、由于动画而更改的视图、触发的计时器等),然后将一堆要执行的方法排队。iOS然后去执行这些方法中的每一个,然后,一旦一切完成,它更新显示。然后下一个运行循环迭代开始。更新显示器的成本很高,所以iOS无法在每一行代码执行后都进行更新。
因此,对于您的代码,当您告诉activityIndicator startAnimating时,它会告诉iOS,在每次运行循环迭代结束时,活动指示器图像需要更新为动画序列中的下一个图像。然后,在iOS到达当前运行循环迭代的末尾之前,调用stopAnimating,它告诉iOS它不再需要更新图像。所以基本上你是在告诉它在开始之前就停止了。
您可以使用Grand Central Dispatch轻松地在不同的线程上运行代码。然而,需要注意的是,任何对UI的更新都必须在主线程上完成。
还要注意,在异步编程时,例如在上面的示例中,您不能从调用它的方法中的异步部分返回值。例如,在上面的例子中,你不能从heavyWork()方法返回繁重工作的结果。这是因为该函数将异步代码调度为在不同的线程上运行,然后立即返回,以便它可以继续当前的运行循环迭代。
SWIFT 4
bejyjqdl3#
SWIFT 5:
wnavrhmk4#
发生这种情况是因为您正在主线程上运行繁重的代码。以这种方式,系统永远没有机会提交图形事务,直到繁重的例程结束。同时提交start和stop方法。
为了避免这种情况,你应该在另一个
dispatch_queue
上运行重载方法,但要注意,大多数UIKit对象不是线程安全的,应该在主队列上再次调度。