Activity 指标未出现
Activity Indicator not appearing
我有一些运行大约 0.2 秒的繁重代码。
我这样设置 activity 指标;然而,它并没有出现,而是整个屏幕冻结了大约 0.2 秒,直到代码完成。
func heavyWork() {
self.actvityIndicator.startAnimating()
...
// heavy loop codes here
...
self.activityIndicator.stopAnimating()
}
这是使用 activity 指标的正确方法吗?
当我注释掉时
// self.activityIndicator.stopAnimating()
activity 指示器出现并停留在那里 - 代码设置正确。
但是UI好像没有及时更新
正如我所说,在繁重的代码完成之前,屏幕只是冻结而不显示 activity 指示器。
发生这种情况是因为您 运行 在主线程上执行繁重的代码。这样,在繁重的例程结束之前,系统永远没有机会提交图形事务。您的启动和停止方法同时提交。
为避免你应该 运行 在另一个 dispatch_queue
上使用重型方法,但要注意大多数 UIKit 对象不是线程安全的,应该在主队列上再次调度。
也许您想继续使用这样的模式:
func heavyWork() {
self.actvityIndicator.startAnimating()
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), { () -> Void in
// ...
// heavy loop codes here
// ...
dispatch_async(dispatch_get_main_queue(), { () -> Void in
self.activityIndicator.stopAnimating()
})
});
}
因为繁重的工作应该在 background 线程中进行,您需要在 main 线程上更新 UI之后。
注意:显然假设您在主线程上调用 func heavyWork()
;如果没有,您可能还需要分散对主线程的初始 UI 更新。
如果您希望应用在执行一些繁重的任务时能够响应,则需要在后台线程上执行它。
大致情况如下:应用程序的主线程在 运行 循环中执行。在每个循环迭代的开始,iOS 检查任何事件(例如用户交互、由于动画而改变的视图、被触发的计时器等),然后将一堆要执行的方法排队。 iOS 然后去执行这些方法中的每一个,然后,一旦一切都完成,它就会更新显示。然后下一个 运行 循环迭代开始。更新显示的成本很高,所以 iOS 不能在每行代码都执行完之后再做。
因此对于您的代码,当您告诉 activityIndicator 开始动画时,它会告诉 iOS 在每个 运行 循环迭代结束时 activity指示器图像需要更新为动画序列中的下一个图像。然后,在 iOS 到达当前 运行 循环迭代的末尾之前,您正在调用 stopAnimating,它告诉 iOS 它不再需要更新图像。所以基本上你告诉它在它开始之前停止。
您可以使用 Grand Central Dispatch 轻松地 运行 在不同的线程上编写代码。然而,重要的是要注意 UI 的任何更新必须 在主线程上完成。
func heavyWork() {
self.activityIndicator.startAnimating()
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) {
// Do heavy work here
dispatch_async(dispatch_get_main_queue()) {
// UI updates must be on main thread
self.activityIndicator.stopAnimating()
}
}
}
另请注意,在异步编程时,例如在上面的示例中,您不能在调用它的方法中 return 来自异步部分的值。例如。在上面的示例中,您不能 return heavyWork() 方法的繁重工作的结果。这是因为该函数将异步代码调度到 运行 在不同的线程上,然后立即 returns 以便它可以继续当前的 运行 循环迭代。
SWIFT 4
func heavyWork() {
activityIndicator.startAnimating()
DispatchQueue.global(qos: .default).async {
// Do heavy work here
DispatchQueue.main.async { [weak self] in
// UI updates must be on main thread
self?.activityIndicator.stopAnimating()
}
}
}
SWIFT 4:
func heavyWork() {
self.actvityIndicator.startAnimating()
DispatchQueue.global(qos: .background).async {
// ...
// heavy loop codes here
// ...
DispatchQueue.main.async {
self.actvityIndicator.stopAnimating()
}
}
}
我有一些运行大约 0.2 秒的繁重代码。
我这样设置 activity 指标;然而,它并没有出现,而是整个屏幕冻结了大约 0.2 秒,直到代码完成。
func heavyWork() {
self.actvityIndicator.startAnimating()
...
// heavy loop codes here
...
self.activityIndicator.stopAnimating()
}
这是使用 activity 指标的正确方法吗?
当我注释掉时
// self.activityIndicator.stopAnimating()
activity 指示器出现并停留在那里 - 代码设置正确。
但是UI好像没有及时更新
正如我所说,在繁重的代码完成之前,屏幕只是冻结而不显示 activity 指示器。
发生这种情况是因为您 运行 在主线程上执行繁重的代码。这样,在繁重的例程结束之前,系统永远没有机会提交图形事务。您的启动和停止方法同时提交。
为避免你应该 运行 在另一个 dispatch_queue
上使用重型方法,但要注意大多数 UIKit 对象不是线程安全的,应该在主队列上再次调度。
也许您想继续使用这样的模式:
func heavyWork() {
self.actvityIndicator.startAnimating()
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), { () -> Void in
// ...
// heavy loop codes here
// ...
dispatch_async(dispatch_get_main_queue(), { () -> Void in
self.activityIndicator.stopAnimating()
})
});
}
因为繁重的工作应该在 background 线程中进行,您需要在 main 线程上更新 UI之后。
注意:显然假设您在主线程上调用 func heavyWork()
;如果没有,您可能还需要分散对主线程的初始 UI 更新。
如果您希望应用在执行一些繁重的任务时能够响应,则需要在后台线程上执行它。
大致情况如下:应用程序的主线程在 运行 循环中执行。在每个循环迭代的开始,iOS 检查任何事件(例如用户交互、由于动画而改变的视图、被触发的计时器等),然后将一堆要执行的方法排队。 iOS 然后去执行这些方法中的每一个,然后,一旦一切都完成,它就会更新显示。然后下一个 运行 循环迭代开始。更新显示的成本很高,所以 iOS 不能在每行代码都执行完之后再做。
因此对于您的代码,当您告诉 activityIndicator 开始动画时,它会告诉 iOS 在每个 运行 循环迭代结束时 activity指示器图像需要更新为动画序列中的下一个图像。然后,在 iOS 到达当前 运行 循环迭代的末尾之前,您正在调用 stopAnimating,它告诉 iOS 它不再需要更新图像。所以基本上你告诉它在它开始之前停止。
您可以使用 Grand Central Dispatch 轻松地 运行 在不同的线程上编写代码。然而,重要的是要注意 UI 的任何更新必须 在主线程上完成。
func heavyWork() {
self.activityIndicator.startAnimating()
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) {
// Do heavy work here
dispatch_async(dispatch_get_main_queue()) {
// UI updates must be on main thread
self.activityIndicator.stopAnimating()
}
}
}
另请注意,在异步编程时,例如在上面的示例中,您不能在调用它的方法中 return 来自异步部分的值。例如。在上面的示例中,您不能 return heavyWork() 方法的繁重工作的结果。这是因为该函数将异步代码调度到 运行 在不同的线程上,然后立即 returns 以便它可以继续当前的 运行 循环迭代。
SWIFT 4
func heavyWork() {
activityIndicator.startAnimating()
DispatchQueue.global(qos: .default).async {
// Do heavy work here
DispatchQueue.main.async { [weak self] in
// UI updates must be on main thread
self?.activityIndicator.stopAnimating()
}
}
}
SWIFT 4:
func heavyWork() {
self.actvityIndicator.startAnimating()
DispatchQueue.global(qos: .background).async {
// ...
// heavy loop codes here
// ...
DispatchQueue.main.async {
self.actvityIndicator.stopAnimating()
}
}
}