在Swift中使用Dispatch_Async更新UI

在我的代码中,我有一个简单的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中使用Dispatch_Async更新UI 的全部内容, 来源链接: utcz.com/qa/435099.html

回到顶部