【问题标题】:Activity Indicator not appearing活动指示器未出现
【发布时间】:2015-07-07 13:19:40
【问题描述】:

我有一些运行大约 0.2 秒的繁重代码。

我这样设置活动指示器;但是,它并没有显示出来,而是整个屏幕冻结了大约 0.2 秒,直到代码完成。

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

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

    self.activityIndicator.stopAnimating()
}

这是使用活动指示器的正确方法吗?

当我注释掉

// self.activityIndicator.stopAnimating()

活动指示器显示并停留在那里 - 代码设置正确。

但 UI 似乎没有在正确的时间更新。

正如我所说,在完成繁重的代码之前,屏幕只是冻结而不显示活动指示器。

【问题讨论】:

  • 您的heavy loop code 是否在后台线程上运行?繁重的循环代码将阻止 UI 显示活动指示器。此外,如果您在后台线程上调用 heavyWork,则 UI 不应更新,因为它不在主线程上。
  • 如果你在后台线程上,你不能在 UI 上修改任何东西;如果你在主线程上,那么它不是做繁重工作的最佳选择。

标签: ios swift activity-indicator


【解决方案1】:

也许您想继续使用这种模式:

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 更新转移到主线程。

【讨论】:

    【解决方案2】:

    如果您希望应用在执行繁重任务时具有响应性,则需要在后台线程上执行它。

    这大致是这里发生的事情:您的应用程序的主线程在运行循环中执行。在每次循环迭代开始时,iOS 会检查任何事件(例如用户交互、由于动画而改变的视图、触发计时器等),然后将一堆方法排入队列以执行。 iOS 然后去执行这些方法中的每一个,然后,一旦一切都完成,它会更新显示。然后下一个运行循环迭代开始。更新显示的成本很高,所以 iOS 不能在每行代码执行完之后再更新。

    因此,在您的代码中,当您告诉 activityIndi​​cator 开始动画时,它会告诉 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()
            }
        }
    }
    

    【讨论】:

    • 感谢您的回答!我整天都在为 DispatchQueue 和活动指示器而苦苦挣扎。
    【解决方案3】:

    SWIFT 4:

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

    【讨论】:

      【解决方案4】:

      这是因为您在主线程上运行繁重的代码。这样,系统在繁重的例程结束之前永远没有机会提交图形事务。您的 start 和 stop 方法同时提交。
      为避免这种情况,您应该在另一个 dispatch_queue 上运行重型方法,但请注意大多数 UIKit 对象不是线程安全的,应在主队列上再次分派。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-01-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-02-04
        • 2016-12-12
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多