У меня много кода в проектах 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, я получаю всевозможные ошибки. Некоторые из них предлагают исправить мой код, но не все исправления дают рабочий код. Что мне делать с этим?

Ответы (6)

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

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

Ваш первый шаг при перемещении любого проекта на Swift 3 должен состоять в том, чтобы открыть его в Xcode 8 и выбрать в меню Edit> Convert> To Current Swift Syntax .... Это применит (с вашей проверкой и одобрением) сразу все изменения, необходимые для всех переименованных 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?")
}

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

Дополнительные советы см. В Руководстве по миграции.

In Xcode 8 beta 4 does not work...

Use:

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

for async two ways:

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

DispatchQueue.main.async( execute: {
    print("Async2")
})

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

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

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

DispatchQueue.global (qos: .background) .async {
    // Фоновый поток
    DispatchQueue.main.async {
        // Запускаем обновления пользовательского интерфейса или блок завершения вызова
    }
}

Swift 4.1 и 5. Мы используем очереди во многих местах нашего кода. Итак, я создал класс Threads со всеми очередями. Если вы не хотите использовать класс Threads, вы можете скопировать желаемый код очереди из методов класса.

class Threads {

  static let concurrentQueue = DispatchQueue(label: "AppNameConcurrentQueue", attributes: .concurrent)
  static let serialQueue = DispatchQueue(label: "AppNameSerialQueue")

  // Main Queue
  class func performTaskInMainQueue(task: @escaping ()->()) {
    DispatchQueue.main.async {
      task()
    }
  }

  // Background Queue
  class func performTaskInBackground(task:@escaping () throws -> ()) {
    DispatchQueue.global(qos: .background).async {
      do {
        try task()
      } catch let error as NSError {
        print("error in background thread:\(error.localizedDescription)")
      }
    }
  }

  // Concurrent Queue
  class func perfromTaskInConcurrentQueue(task:@escaping () throws -> ()) {
    concurrentQueue.async {
      do {
        try task()
      } catch let error as NSError {
        print("error in Concurrent Queue:\(error.localizedDescription)")
      }
    }
  }

  // Serial Queue
  class func perfromTaskInSerialQueue(task:@escaping () throws -> ()) {
    serialQueue.async {
      do {
        try task()
      } catch let error as NSError {
        print("error in Serial Queue:\(error.localizedDescription)")
      }
    }
  }

  // Perform task afterDelay
  class func performTaskAfterDealy(_ timeInteval: TimeInterval, _ task:@escaping () -> ()) {
    DispatchQueue.main.asyncAfter(deadline: (.now() + timeInteval)) {
      task()
    }
  }
}

Пример использования основной очереди.

override func viewDidLoad() {
    super.viewDidLoad()
     Threads.performTaskInMainQueue {
        //Update UI
    }
}

Swift 5.2, 4 и новее

Основная и фоновая очереди

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

Работа с async и sync нитями!

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

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

Потоки синхронизации блокируют основной поток во время выполнения.

2022 WebDevInsider