Как мне отправить синхронизацию, отправить асинхронность, отправить после и т. д. В Swift 3, Swift 4 и за его пределами?


у меня есть много кода в 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")
}

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

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

6 209

6 ответов:

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

в бета-версии Xcode 8 / Swift 3 Apple применила эту функцию (наряду с несколькими другими), чтобы сделать структуру отправки намного более быстрой. (И Ядра Графика тоже.) Если вы следили за стремительными усилиями с открытым исходным кодом,это не новость, но теперь это первый раз, когда это часть 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?")
}

вы можете найти свой путь вокруг нового диспетчерского API, открыв его интерфейс в Xcode 8 -- use Open Быстро найти модуль отправки, или поставить символ (например DispatchQueue) в вашем Swift project/playground и command-click it, а затем brouse вокруг модуля оттуда. (Вы можете найти Swift отправка API на новом веб-сайте Apple spiffy New API Reference и в средстве просмотра документов Xcode, но похоже, что содержимое doc из версии C еще не перешло в него.)

посмотреть Руководство По Миграции для получения дополнительных советов.

в Xcode 8 бета 4 не работает...

использование:

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

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

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

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

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

DispatchQueue.global(qos: .background).async {
    // Background Thread
    DispatchQueue.main.async {
        // Run UI Updates or call completion block
    }
}

в Xcode 8 использовать:

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

Swift 4

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

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

работа с async и синхронизация нити!

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

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

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

Swift 4.1. Мы используем очереди во многих местах в коде. Итак, я создал класс 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 {
        self.tblViewSignUP.reloadData()
    }
}