Вашего цикл не будет иметь возможности для обновления пользовательского интерфейса в этом главном потоке, если сам цикл не выполняется в другом потоке. Таким образом, вы можете отправить его в какую-то фоновую очередь. В 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)
}
}
}
Если обновление пользовательского интерфейса происходит быстрее из фонового потока, чем пользовательский интерфейс может обрабатывать их, основной поток может зависеть от запросов на обновление (что делает его намного медленнее, чем на самом деле). Чтобы решить эту проблему, можно рассмотреть возможность использования источника отправки, чтобы отделить задачу «Обновление UI» от фактического процесса обновления фона.
можно использовать DispatchSourceUserDataAdd
(в Swift 2, это dispatch_source_t
из DISPATCH_SOURCE_TYPE_DATA_ADD
), должности add
звонков (dispatch_source_merge_data
в Swift 2) от фонового потока так часто, как это необходимо, и пользовательский интерфейс будет обрабатывать их так быстро, как это возможно , но объединит их вместе, когда он называет data
(dispatch_source_get_data
в Swift 2), если обновления фона поступают быстрее, чем пользовательский интерфейс может их обработать. Это обеспечивает максимальную производительность фона при оптимальных обновлениях пользовательского интерфейса, но что более важно, это гарантирует, что пользовательский интерфейс не станет узким местом.
Итак, сначала объявить некоторую переменную для отслеживания прогресса:
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);
}
}
Можете ли вы подтвердить, что вызов setProgress стреляет? Попытайтесь бросить туда какую-то регистрацию или контрольную точку регистрации. Также обычно предпочтительнее использовать NSOperation для вещей, которые используют Cocoa. – macshome
Интересно, я бросил несколько протоколов, и кажется, что вызов setProgress не срабатывает. Почему это так? – dslkfjsdlfjl
Ну, когда вы отправляете_асинк, это зависит от системы, когда она собирается срабатывать. Если вам нужно, чтобы пользовательский интерфейс обновлялся своевременно, не используйте async. В Xcode вы можете приостановить приложение и взглянуть на ожидающие блоки. – macshome