swift 活动指示器未显示

ecfsfe2w  于 2023-06-21  发布在  Swift
关注(0)|答案(4)|浏览(107)

我有一些很重的代码,运行时间大约为0.2秒。
我这样设置活动指示器;然而,它并没有显示出来,而是整个屏幕冻结了大约0.2秒,直到代码完成。

func heavyWork() {
    self.actvityIndicator.startAnimating()

    ...
    // heavy loop codes here
    ...

    self.activityIndicator.stopAnimating()
}

这是使用活动指示器的正确方法吗?
当我评论出来

// self.activityIndicator.stopAnimating()

活动指示器显示并停留在那里-代码设置正确。
但是UI似乎没有在正确的时间更新。
正如我所说,屏幕只是冻结而不显示活动指示器,直到繁重的代码完成。

dphi5xsq

dphi5xsq1#

也许你想继续这样的模式:

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()
        })
    });
}

因为繁重的工作应该发生在一个 * 后台 * 线程,你需要在一个 * 主 * 线程后更新UI。

  • 注意:显然,假设您在主线程上调用 * func heavyWork();如果没有,你可能需要将最初的UI更新转移到主线程。
jbose2ul

jbose2ul2#

如果你想让应用程序在执行一些繁重的任务时响应,你需要在后台线程上执行它。
这大概是这里发生的事情:应用的主线程在run循环中执行。在每次循环迭代开始时,iOS检查任何事件(例如用户交互、由于动画而更改的视图、触发的计时器等),然后将一堆要执行的方法排队。iOS然后去执行这些方法中的每一个,然后,一旦一切完成,它更新显示。然后下一个运行循环迭代开始。更新显示器的成本很高,所以iOS无法在每一行代码执行后都进行更新。
因此,对于您的代码,当您告诉activityIndicator startAnimating时,它会告诉iOS,在每次运行循环迭代结束时,活动指示器图像需要更新为动画序列中的下一个图像。然后,在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()
        }
    }
}

还要注意,在异步编程时,例如在上面的示例中,您不能从调用它的方法中的异步部分返回值。例如,在上面的例子中,你不能从heavyWork()方法返回繁重工作的结果。这是因为该函数将异步代码调度为在不同的线程上运行,然后立即返回,以便它可以继续当前的运行循环迭代。

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()
        }
    }
}
bejyjqdl

bejyjqdl3#

SWIFT 5:

func heavyWork() {
    activityIndicator.startAnimating()
    
    DispatchQueue.global(qos: .background).async {
        
        // ...
        // heavy loop codes here
        // ...
        
        DispatchQueue.main.async {
            self.activityIndicator.stopAnimating()
        }
    }
}
wnavrhmk

wnavrhmk4#

发生这种情况是因为您正在主线程上运行繁重的代码。以这种方式,系统永远没有机会提交图形事务,直到繁重的例程结束。同时提交start和stop方法。
为了避免这种情况,你应该在另一个dispatch_queue上运行重载方法,但要注意,大多数UIKit对象不是线程安全的,应该在主队列上再次调度。

相关问题