您好, 欢迎来到 !    登录 | 注册 | | 设为首页 | 收藏本站

在Swift中使用Dispatch_Async更新UI

在Swift中使用Dispatch_Async更新UI

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

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

还要注意,进度是一个从0.0到1.0的数字,因此您大概想除以循环的最大迭代次数

如果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 2022/1/1 18:17:16 有280人围观

撰写回答


你尚未登录,登录后可以

和开发者交流问题的细节

关注并接收问题和回答的更新提醒

参与内容的编辑和改进,让解决方法与时俱进

请先登录

推荐问题


联系我
置顶