SwiftでGCDメインスレッドのパラメーターでメソッドを呼び出す方法は?


192

私のアプリには、NSRURLSessionを作成してNSURLRequestを送信する関数があります。

sesh.dataTaskWithRequest(req, completionHandler: {(data, response, error)

このタスクの完了ブロックでは、UIImageを呼び出し側のビューコントローラーに追加する計算を行う必要があります。という機能があります

func displayQRCode(receiveAddr, withAmountInBTC:amountBTC)

UIImageを追加する計算を行います。完了ブロック内でビュー追加コードを実行しようとすると、Xcodeは、バックグラウンドプロセス中にレイアウトエンジンを使用できないことを示すエラーをスローします。だから私はメインスレッドでメソッドをキューに入れようとするSOのコードを見つけました:

let time = dispatch_time(DISPATCH_TIME_NOW, Int64(0.0 * Double(NSEC_PER_MSEC)))

dispatch_after(time, dispatch_get_main_queue(), {
    let returned = UIApplication.sharedApplication().sendAction("displayQRCode:", to: self.delegate, from: self, forEvent: nil)
})

ただし、この関数呼び出しにパラメーター「receiveAddr」および「amountBTC」を追加する方法がわかりません。これをどのように行うのですか、または誰かがアプリケーションのメインキューにメソッド呼び出しを追加するための最適な方法を提案できますか?

回答:


496

Swiftの最新バージョンはDispatchQueue.main.async、メインスレッドへのディスパッチに使用します。

DispatchQueue.main.async { 
  // your code here
}

後の発送とメインキューには、次を使用します。

DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
  // your code here
}

使用されているSwiftの古いバージョン:

dispatch_async(dispatch_get_main_queue(), {
  let delegateObj = UIApplication.sharedApplication().delegate as YourAppDelegateClass
  delegateObj.addUIImage("yourstring")
})

あなたの提案が機能していることは正しいですが、UIApplication.sharedApplicationへの呼び出しを行わないため、私の答えは少し優れていると思います。私の答えの範囲は重要なオブジェクトに制限されていますが、あなたの答えは、私が何をしているかを正確に学ぶためにもっと多くのドキュメントを読む必要がある補助的なオブジェクトを持ち込みます。また、元の質問を編集して、正しい関数呼び出しを含めました。displayQRCodeは十分に具体的ではないと思っていましたが、今のコメントではそうです。ご指摘いただきありがとうございます。
almel 2014

84

Swift 3+およびSwift 4バージョン:

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

Swift 3およびXcode 9.2:

dispatch_async_on_main_queue {
    print("Hello")
}

15

スウィフト2

後続クロージャを使用すると、次のようになります。

dispatch_async(dispatch_get_main_queue()) {
    self.tableView.reloadData()
}

Trailing Closuresは、関数パラメータースコープの外部でクロージャーを定義できるようにするSwift構文糖衣です。詳細については、Swift 2.2プログラミング言語ガイドの末尾クロージャを参照してください。

dispatch_async場合にAPIであるfunc dispatch_async(queue: dispatch_queue_t, _ block: dispatch_block_t)ためdispatch_block_tの型の別名である() -> VoidAの0パラメータを受け取り、戻り値を持たない閉鎖、及びブロック我々は外範囲でクロージャを定義することができる関数の最後のパラメータであります- dispatch_async


1
それはまさに私が探している3行でした...今、私の心を読むのをやめることができます
Laszlo

8

メインスレッドでcollectionViewをリロードします

DispatchQueue.main.async {
    self.collectionView.reloadData()
}

7

他の回答と同じ結果を達成するためのより良い(IMO)Swifty / Cocoaスタイルの構文を次に示します。

NSOperationQueue.mainQueue().addOperationWithBlock({
    // Your code here
})

または、人気のあるAsync Swiftライブラリ入手して、コードを減らして機能性を高めることもできます。

Async.main {
    // Your code here
}

メソッドの名前を変更OperationQueue.main.addOperation({ }
Frostmourne

3

これを行う適切な方法は、次のコードで行ったように、main_queueでdispatch_asyncを使用することです。

dispatch_async(dispatch_get_main_queue(), {
    (self.delegate as TBGQRCodeViewController).displayQRCode(receiveAddr, withAmountInBTC:amountBTC)
})

2

次に、より良い構文に追加できる素敵な小さなグローバル関数を示します。

func dispatch_on_main(block: dispatch_block_t) {
    dispatch_async(dispatch_get_main_queue(), block)
}

そして使い方

dispatch_on_main {
    // Do some UI stuff
}

2
//Perform some task and update UI immediately.
DispatchQueue.global(qos: .userInitiated).async {  
    // Call your function here
    DispatchQueue.main.async {  
        // Update UI
        self.tableView.reloadData()  
    }
}

//To call or execute function after some time
DispatchQueue.main.asyncAfter(deadline: .now() + 5.0) {
    //Here call your function
}

//If you want to do changes in UI use this
DispatchQueue.main.async(execute: {
    //Update UI
    self.tableView.reloadData()
})

2

クロージャー内でセルフを使用している場合は、セルフを弱めることを忘れないでください。

dispatch_async(dispatch_get_main_queue(),{ [weak self] () -> () in
    if let strongSelf = self {
        self?.doSomething()
    }
})

1
なぜこれを行うべきなのか説明してもらえますか?
Jackspicer 2016年

それは、それがメモリサイクルを作成する可能性があるためです。つまり、私は何かへの強い参照があり、私への強い参照があります。どちらもメモリヒープから離れることができないことを意味します。
jackofallcode 2017年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.