Как я могу отправить dispatch_sync, dispatch_async, dispatch_after и т. Д. В Swift 3, Swift 4 и далее?

176

У меня есть много кода в проектах Swift 2.x(или даже 1.x), которые выглядят следующим образом:

// Move to a background thread to do some long running work
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) {
    let image = self.loadOrGenerateAnImage()
    // Bounce back to the main thread to update the UI
    dispatch_async(dispatch_get_main_queue()) {
        self.imageView.image = image
    }
}

Или что-то вроде этого для задержки выполнения:

dispatch_after(dispatch_time(DISPATCH_TIME_NOW, Int64(0.5 * Double(NSEC_PER_SEC))), dispatch_get_main_queue()) {
    print("test")
}

Или любое из других видов использования Grand Central Dispatch API...

Теперь, когда я открыл свой проект в Xcode 8 (бета) для Swift 3, я получаю всевозможные ошибки. Некоторые из них предлагают исправить мой код, но не все исправления производят рабочий код. Halp! Что мне делать с этим?

Теги:
grand-central-dispatch
swift3
libdispatch

5 ответов

257
Лучший ответ

С самого начала Swift предоставил некоторые возможности для создания ObjC и C более Swifty, добавляя больше с каждой версией. Теперь в Swift 3 новая функция import as member позволяет создавать фреймворки с определенными стилями C API, где у вас есть тип данных, который работает как класс, и куча глобальных функций для работы с ним - больше походит на Swift-native API. Импорт типов данных как классов Swift, их связанных глобальных функций, импортируемых как методы и свойства этих классов, и некоторые связанные с ними вещи, такие как наборы констант, могут при необходимости становиться подтипами.

В Xcode 8/Swift 3 beta Apple применила эту функцию (наряду с несколькими другими), чтобы сделать платформу Dispatch намного более Swifty. (И Core Graphics). Если вы следовали за усилиями с открытым исходным кодом Swift, это не новость, но теперь это первый раз, когда он является частью Xcode.

Первым шагом при перемещении любого проекта в Swift 3 должно быть открытие его в Xcode 8 и в меню выберите "Редактирование" > "Преобразовать" > "Текущий синтаксис Swift".... Это применит (с вашим обзором и одобрением) все изменения, необходимые для всех переименованных API и других изменений. (Часто на строку кода влияет более чем одно из этих изменений сразу, поэтому реагирование на исправление ошибок - по отдельности может не справиться со всем правильным.)

Результат состоит в том, что общий шаблон для отскока работы на фоне и обратно теперь выглядит следующим образом:

// Move to a background thread to do some long running work
DispatchQueue.global(qos: .userInitiated).async {
    let image = self.loadOrGenerateAnImage()
    // Bounce back to the main thread to update the UI
    DispatchQueue.main.async {
        self.imageView.image = image
    }
}

Обратите внимание, что мы используем .userInitiated вместо одной из старых констант DISPATCH_QUEUE_PRIORITY. Спецификаторы качества обслуживания (QoS) были представлены в OS X 10.10/iOS 8.0, предоставляя более четкий способ для системы расставить приоритеты в работе и отказаться от старых спецификаторов приоритета. Подробнее см. Apple документы о фоновой работе и энергоэффективности.

Кстати, если вы сохраняете собственные очереди для организации работы, способ получить ее теперь выглядит следующим образом (обратите внимание, что DispatchQueueAttributes - это OptionSet, поэтому вы используете литералы в стиле коллекции, чтобы комбинировать параметры ):

class Foo { 
    let queue = DispatchQueue(label: "com.example.my-serial-queue",
                           attributes: [.serial, .qosUtility])
    func doStuff() {
        queue.async {
            print("Hello World")
        }
    }
}

С помощью dispatch_after выполните работу позже? Это также метод в очередях, и он принимает DispatchTime, который имеет операторы для различных числовых типов, поэтому вы можете просто добавить целые или дробные секунды:

DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { // in half a second...
    print("Are we there yet?")
}

Вы можете найти свой путь вокруг нового API-интерфейса отправки, открыв его интерфейс в Xcode 8 - используйте Open Quickly, чтобы найти модуль Dispatch, или поместите символ (например, DispatchQueue) в ваш проект Swift/playground и командную строку, щелкните по нему, а затем разглядывайте модуль. (Вы можете найти API Swift Dispatch в новом веб-сайте API Reference и в приложении Xcode doc, но это похоже на содержимое документа из версии C еще не переместился в нее.)

Подробнее см. в Руководство по миграции.

  • 3
    Что касается Xcode 8 Beta 6, атрибут .serial исчез и поведение по умолчанию - forums.developer.apple.com/message/159457#159457
  • 6
    Это требует обновления с XCode 8.1 .. метка атрибутов исчезла, и вместо нее мы можем использовать 'DispatchQueue.global (qos: .background) .async'
Показать ещё 6 комментариев
109

в xcode 8 beta 4 не работает. Использование:

DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
    print("Are we there yet?")
}

для асинхронизации двумя способами:

DispatchQueue.main.async {
    print("Async1")
}

DispatchQueue.main.async( execute: {
    print("Async2")
})
  • 0
    идеально подходит для меня (xCode 9.4.1)
  • 0
    Так что это не блокирует интерфейс?
32

в xcode8 используйте:

DispatchQueue.global(qos: .userInitiated).async { }
25

Это хороший пример для Swift 3 около async:

DispatchQueue.global(qos: .background).async {
    // Background Thread
    DispatchQueue.main.async {
        // Run UI Updates
    }
}
  • 0
    hi DispatchQueue.main.async {// Запуск обновлений пользовательского интерфейса} выполняется до фонового потока
  • 0
    похожи с соплинами Котлина
8

Swift 4

Основные и фоновые очереди

let main = DispatchQueue.main
let background = DispatchQueue.global()
let helper = DispatchQueue(label: "another_thread") 

Работа с потоками асинхронной и синхронизации!

 background.async { //async tasks here } 
 background.sync { //sync tasks here } 

Асинхронные потоки будут работать вместе с основным потоком.

Синхронизирующие потоки будут блокировать основной поток при выполнении.

  • 1
    А как бы вы использовали синхронизацию потоков без блокировки основного потока (UI) ?? Я хотел бы выполнить ряд вещей в фоновом режиме - но эти вещи должны выполняться синхронно друг за другом. В течение этого времени пользовательский интерфейс должен оставаться отзывчивым .... Как бы вы это сделали?
  • 0
    Используйте NSOperationQueue. Какая ваша каждая задача представляет NSOperation. см. stackoverflow.com/a/19746890/5215474
Показать ещё 1 комментарий

Ещё вопросы

Сообщество Overcoder
Наверх
Меню