当前位置: 首页 > 面试题库 >

在Swift中使用Dispatch_Async更新UI

晁英彦
2023-03-14
问题内容

在我的代码中,我有一个简单的for循环,使用嵌套的for循环循环100次以创建延迟。延迟之后,我将通过dispatch_async更新UI中的进度视图元素。但是,我无法更新UI。有谁知道为什么用户界面没有更新?注意:下面的print语句用于验证for循环是否正确循环。

for i in 0..<100 {

    //Used to create a delay
    for var x = 0; x<100000; x++ {
        for var z = 0; z<1000; z++ {

        }
    }

    println(i)

    dispatch_async(dispatch_get_main_queue()) {
        // update some UI
        self.progressView.setProgress(Float(i), animated: true)

    }
  }

问题答案:

三种观察,两种基本观察,一种更为先进:

  1. 除非循环本身在另一个线程上运行,否则循环将无法更新该主线程中的UI。因此,您可以将其分派到某些后台队列。在Swift 3中
    DispatchQueue.global(qos: .utility).async {
    for i in 0 ..< kNumberOfIterations {
    
        // do something time consuming here
    
        DispatchQueue.main.async {
            // now update UI on main thread
            self.progressView.setProgress(Float(i) / Float(kNumberOfIterations), animated: true)
        }
    }
    

    }

在Swift 2中:

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) {
    for i in 0 ..< kNumberOfIterations {

        // do something time consuming here

        dispatch_async(dispatch_get_main_queue()) {
            // now update UI on main thread
            self.progressView.setProgress(Float(i) / Float(kNumberOfIterations), animated: true)
        }
    }
}
  1. 还要注意,进度是一个从0.0到1.0的数字,因此您大概想除以循环的最大迭代次数。

  2. 如果UI更新来自后台线程的速度快于UI无法处理的速度,则主线程可能会被更新请求积压(这使它看起来比实际速度慢得多)。为了解决这个问题,可以考虑使用调度源将“更新UI”任务与实际的后台更新过程分离。

可以使用DispatchSourceUserDataAdd(在Swift
2中dispatch_source_tDISPATCH_SOURCE_TYPE_DATA_ADD),在后台线程中根据需要频繁地发布add调用(dispatch_source_merge_data在Swift
2中为),UI会尽快处理它们,但在调用时将它们合并在一起datadispatch_source_get_data在Swift
2中),如果后台更新的传入速度比UI可以处理它们的速度更快。这样可以通过最佳的UI更新获得最大的后台性能,但是更重要的是,这可以确保UI不会成为瓶颈。


因此,首先声明一些变量以跟踪进度:

    var progressCounter: UInt = 0

现在,您的循环可以创建一个源,定义源更新时的操作,然后启动异步循环来更新源。在Swift 3中:

    progressCounter = 0

// create dispatch source that will handle events on main queue

let source = DispatchSource.makeUserDataAddSource(queue: .main)

// tell it what to do when source events take place

source.setEventHandler() { [unowned self] in
    self.progressCounter += source.data

    self.progressView.setProgress(Float(self.progressCounter) / Float(kNumberOfIterations), animated: true)
}

// start the source

source.resume()

// now start loop in the background

DispatchQueue.global(qos: .utility).async {
    for i in 0 ..< kNumberOfIterations {
        // do something time consuming here

        // now update the dispatch source

        source.add(data: 1)
    }
}

在Swift 2中:

    progressCounter = 0

// create dispatch source that will handle events on main queue

let source = dispatch_source_create(DISPATCH_SOURCE_TYPE_DATA_ADD, 0, 0, dispatch_get_main_queue());

// tell it what to do when source events take place

dispatch_source_set_event_handler(source) { [unowned self] in
    self.progressCounter += dispatch_source_get_data(source)

    self.progressView.setProgress(Float(self.progressCounter) / Float(kNumberOfIterations), animated: true)
}

// start the source

dispatch_resume(source)

// now start loop in the background

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) {
    for i in 0 ..< kNumberOfIterations {

        // do something time consuming here

        // now update the dispatch source

        dispatch_source_merge_data(source, 1);
    }
}


 类似资料:
  • 问题内容: 我在Swift 2.x(甚至1.x)项目中有很多代码,如下所示: 或类似这样的东西来延迟执行: 或Grand Central Dispatch API的所有其他各种用途… 既然我已经在Swift 3的Xcode 8(测试版)中打开了我的项目,就会遇到各种各样的错误。其中一些提供了修复我的代码的功能,但并非所有修复都可以产生有效的代码。我该怎么办? 问题答案: 从一开始,Swift就提供

  • 问题内容: 我在使用iOS SDK 8的Swift时遇到一个问题 我使用了回调来获取数据背景,并且在获取数据时,我想设置一个文本字段值并更新屏幕。 这是我的代码: 运行此代码,将正确获取数据并且txtTest没有更新,但是当我点击txtTest时,将显示该值。那么有什么方法可以强制更新UI?或向UI线程发送消息? 问题答案: 每个人都想在Swift中进行UI更新时遇到的同一问题:永远不要在任何辅助

  • 问题内容: 我正在使用swift构建RSS阅读器,并且需要实现pull来重新加载功能。 这是我试图做到的方式。 我正进入(状态 : super.init调用未初始化属性“ self.refresh” 请帮助我了解手势识别器的行为。一个有效的示例代码将有很大的帮助。 谢谢。 问题答案: 拉动刷新 是iOS内置的。你可以像这样迅速 在某些时候,您可能会刷新。

  • 问题内容: 使用以下代码,应用程序编译后,我立即在徽章图标中得到(2): 我确实尝试了下一个变体:初始化一个新的版本,然后再更新: 但是,当我收到新通知时,它不会更新为+1。有谁知道如何解决? 问题答案: 除非实际打开应用程序,否则不会使用此方法更新徽章编号。如果要在收到通知时更新徽章编号,则需要将json推送通知的Badge属性设置为所需编号。 如果您发送的是普通消息(不使用json),则可以通

  • 问题内容: 我的桌子: 我需要使用,按ID分组来更新字段: 对于ID 1,应为 对于ID 2,应为 预期输出: 我该如何看重? 我的代码: 这是行不通的。 问题答案: 不幸的是,您无法在中更新与其自身联接的表。 您需要创建一个函数作为解决方法:

  • 本文向大家介绍使用findOneAndUpdate()在MongoDB中更新?,包括了使用findOneAndUpdate()在MongoDB中更新?的使用技巧和注意事项,需要的朋友参考一下 将用于更新基于过滤和排序条件,即一个单一的文件- 让我们创建一个包含文档的集合- 在方法的帮助下显示集合中的所有文档- 这将产生以下输出- 以下是要使用更新的查询。在这里,我们增加特定文档的字段Marks-