Поиск…
Вступление
Связанная тема: Grand Central Dispatch
Синтаксис
- dispatch_async - запускает блок кода в отдельной очереди и не останавливает текущую очередь. Если очередь находится в другом потоке, чем тот, на который был вызван метод dispatch_async, код в блоке будет работать во время кода после того, как dispatch_async также будет запущен
- dispatch_sync - Выполняет блок кода в отдельной очереди, и не остановить текущую очередь. Если очередь находится в другом потоке, чем тот, на который был вызван метод dispatch_async, будет выполняться код в блоке, а выполнение в потоке, где был вызван метод, будет возобновляться только после завершения
параметры
очередь | Очередь, в которой будет выполняться код в блоке отправки. Очередь похожа (но не совсем такая же, как) на поток; код в разных очередях может выполняться параллельно. Используйте dispatch_get_main_queue чтобы получить очередь для основного потока. Чтобы создать новую очередь, которая, в свою очередь, создает новый поток, используйте dispatch_queue_create("QUEUE_NAME", DISPATCH_QUEUE_CONCURRENT) . Первый параметр - это имя очереди, которое отображается в отладчике, если вы приостановили пока блок все еще работает. Второй параметр не имеет значения, если вы не хотите использовать одну и ту же очередь для нескольких вызовов dispatch_async или dispatch_sync . В нем описывается, что происходит, когда другой блок помещается в одну очередь; DISPATCH_QUEUE_CONCURRENT вызовет запуск обоих блоков одновременно, в то время как DISPATCH_QUEUE_SERIAL заставит второй блок ждать завершения первого блока |
---|---|
блок | Код в этом блоке будет запущен в очереди queue ; введите код, который вы хотите запустить в отдельной очереди. Полезный совет: если вы пишете это в Xcode, а аргумент блока имеет синий контур вокруг него, дважды щелкните по аргументу, и Xcode автоматически сделает пустой блок (это относится ко всем блочным аргументам в любой функции или методе) |
замечания
Всякий раз, когда вы делаете что-то в отдельном потоке, который возникает при использовании очередей, важно поддерживать безопасность потоков. Некоторые методы, в частности, для UIView
s, могут не работать и / или сбой в потоках, отличных от основного потока. Кроме того, убедитесь, что вы ничего не меняете (переменные, свойства и т. Д.), Которые также используются в основном потоке, если вы не учитываете это изменение
Запуск кода одновременно - Запуск кода при запуске другого кода
Скажите, что вы хотите выполнить в действии (в этом случае записывать «Foo»), делая что-то еще (записывая «Bar»). Обычно, если вы не используете параллелизм, одно из этих действий будет полностью выполнено, а другой запуск будет выполняться только после того, как он будет полностью завершен. Но с параллелизмом вы можете одновременно запускать оба действия:
dispatch_async(dispatch_queue_create("Foo", DISPATCH_QUEUE_CONCURRENT), ^{
for (int i = 0; i < 100; i++) {
NSLog(@"Foo");
usleep(100000);
}
});
for (int i = 0; i < 100; i++) {
NSLog(@"Bar");
usleep(50000);
}
Это будет записывать «Foo» 100 раз, приостанавливаясь на 100 мсек каждый раз, когда он регистрируется, но он будет делать все это в отдельном потоке. В то время как Foo
регистрируется, «Bar» также будет регистрироваться через 50 мс в одно и то же время. В идеале вы должны увидеть результат с сочетаниями «Foo» и «Bars»
Выполнение основной темы
При асинхронном выполнении задач обычно возникает необходимость обеспечить выполнение части кода в основном потоке. Например, вам может понадобиться асинхронно удалять REST API, но поместить результат в UILabel на экране. Перед обновлением UILabel вы должны убедиться, что ваш код запущен в основном потоке:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
//Perform expensive tasks
//...
//Now before updating the UI, ensure we are back on the main thread
dispatch_async(dispatch_get_main_queue(), ^{
label.text = //....
});
}
Всякий раз, когда вы обновляете представления на экране, всегда убедитесь, что вы делаете это в основном потоке, иначе может возникнуть неопределенное поведение.
Диспетчерская группа - ждет завершения других потоков.
dispatch_group_t preapreWaitingGroup = dispatch_group_create();
dispatch_group_enter(preapreWaitingGroup);
[self doAsynchronousTaskWithComplete:^(id someResults, NSError *error) {
// Notify that this task has been completed.
dispatch_group_leave(preapreWaitingGroup);
}]
dispatch_group_enter(preapreWaitingGroup);
[self doOtherAsynchronousTaskWithComplete:^(id someResults, NSError *error) {
dispatch_group_leave(preapreWaitingGroup);
}]
dispatch_group_notify(preapreWaitingGroup, dispatch_get_main_queue(), ^{
// This block will be executed once all above threads completed and call dispatch_group_leave
NSLog(@"Prepare completed. I'm readyyyy");
});
Обновление 1. Версия Swift 3.
let prepareGroup = DispatchGroup()
prepareGroup.enter()
doAsynchronousTaskWithComplete() { (someResults, error) in
// Notify that this task has been completed.
prepareGroup.leave()
}
prepareGroup.enter()
doOtherAsynchronousTaskWithComplete() { (someResults, error) in
// Notify that this task has been completed.
prepareGroup.leave()
}
prepareGroup.notify(queue: DispatchQueue.main) {
// This block will be executed once all above threads completed and call dispatch_group_leave
print("Prepare completed. I'm readyyyy")
}