Swift 3、Swift 4以降で、dispatch_sync、dispatch_async、dispatch_afterなどを行うにはどうすればよいですか?


243

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の他のあらゆる種類の用途のいずれか...

Swift 3のXcode 8(ベータ版)でプロジェクトを開いたので、あらゆる種類のエラーが発生します。それらのいくつかは私のコードを修正することを提案していますが、すべての修正が機能するコードを生成するわけではありません。これについて私は何をしますか?


回答:


343

当初から、SwiftはObjCとCをより迅速にするためのいくつかの機能を提供しており、バージョンごとにさらに追加しています。現在、Swift 3では、新しい「メンバーとしてインポート」機能により、特定のスタイルのC APIを持つフレームワークを使用できます-クラスのように機能するデータ型と、それを操作するための一連のグローバル関数があります- SwiftネイティブAPIのように動作します。データ型はSwiftクラスとしてインポートされ、それらに関連するグローバル関数はそれらのクラスのメソッドおよびプロパティとしてインポートされます。定数のセットなどのいくつかの関連するものは、必要に応じてサブタイプになります。

Xcode 8 / Swift 3ベータでは、Appleはこの機能を(他のいくつかと同様に)適用して、Dispatchフレームワークをより迅速にしています。(そしてCore Graphicsも。)あなたがSwiftオープンソースの取り組みを続けてきたなら、これはニュースはありませんが、Xcodeの一部となったのは今回が初めてです。

プロジェクトをSwift 3に移動する最初のステップは、Xcode 8でプロジェクトを開き、メニューで[編集]> [変換]> [現在のSwift構文... ]を選択することです。これは、名前を変更したすべてのAPIとその他の変更に必要なすべての変更を(レビューと承認と共に)一度に適用します。(多くの場合、コード行はこれらの変更の1つ以上の影響を受けます。そのため、エラー修正に応答することは、個別にすべてを正しく処理できない可能性があります。)

その結果、作業をバックグラウンドに跳ね返して戻すための一般的なパターンは次のようになります。

// 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定数の代わりに使用していることに注意してください。Quality of Service(QoS)指定子はOS X 10.10 / iOS 8.0で導入され、システムが作業に優先順位を付け、古い優先度指定子を非推奨にする明確な方法を提供します。詳細については、バックグラウンド作業とエネルギー効率に関する Appleのドキュメントを参照してください。

ちなみに、作業を整理するために独自のキューを保持している場合、取得する方法は次のようになります(これDispatchQueueAttributesOptionSetなので、コレクションスタイルのリテラルを使用してオプションを組み合わせます)。

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?")
}

Xcode 8でインターフェースを開くことにより、新しいDispatch APIを回避する方法を見つけることができますDispatchQueue-Open Quicklyを使用してDispatchモジュールを見つけるか、Swiftプロジェクト/プレイグラウンドにシンボル(など)を配置してコマンドクリックしてからブラウジングしますそこからモジュール。(Swift Dispatch APIは、Appleの新しいAPIリファレンスのWebサイトとXcode内のドキュメントビューアーで見つけることができますが、Cバージョンのドキュメントコンテンツはまだ移動されていないようです。)

その他のヒントについては、移行ガイドをご覧ください。


3
Xcode 8 Beta 6に関しては、.serial属性はなくなり、デフォルトの動作-forums.developer.apple.com/message/159457#159457
hyouuu

6
XCode 8.1以降の更新が必要です。属性ラベルが消え、代わりに「DispatchQueue.global(qos:.background).async」を使用できます
Mike M

2
素晴らしい答え。本当に頭を抱える手助けをしてくれました。
Mohsin Khubaib Ahmed

私はqos:代わりに使用しなければなりませんでしたattributes:
Islam Q.

それmyQueue.async {class Foo例ではありませんか?
vacawama 2017年

142

Xcode 8ベータ4では動作しません...

使用する:

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

非同期の2つの方法:

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

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

それでUIをブロックしないのですか?
user25

72

これはSwift 4約の良い例ですasync

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

hi DispatchQueue.main.async {// Run UI Updates}がバックグラウンドスレッドの前に実行されています
Uma Achanta

Kotlinのコルーチンと似ています
user25

40

Xcode 8で使用:

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

26

Swift 5.2、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)をブロックせずに同期スレッドをどのように使用しますか?一連の処理をバックグラウンドで実行したいのですが、これらの処理は同期して次々と実行する必要があります。この間、UIは応答性を維持する必要があります。
iKK 2018

NSOperationQueueを使用します。NSOperationを表す各タスク。stackoverflow.com/a/19746890/5215474を
サランジス2018年

12

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
    }
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.