web-dev-qa-db-ja.com

SwiftではどのようにGCDのメインスレッド上のパラメータでメソッドを呼び出すのですか?

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

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

このタスクの完了ブロックでは、呼び出し側のViewControllerに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"を追加する方法がわかりません。これをどのように行うのでしょうか。それともアプリケーションのメインキューにメソッド呼び出しを追加するための最適な方法を誰かが提案することができますか?

174
almel

これをcompletion handlerに書くだけです。dispatch_afterを使う必要はありません。

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

Swift 3/4:

DispatchQueue.main.async { 
  let delegateObj = UIApplication.sharedApplication().delegate as YourAppDelegateClass
  delegateObj.addUIImage("yourstring")
}

メインキューでのディスパッチ後も

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

YourAppDelegateClassをあなたがデリゲートクラスに置き換えます

445
codester

Swift 3とSwift 4のバージョン

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

Swift3とXCode 9.2:

dispatch_async_on_main_queue {
     //Your code
     print("Hello")
 }
74
DazChong

スイフト2

トレーリングクロージャを使用すると、これは次のようになります。

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

Trailing ClosuresはSwiftの構文糖衣で、関数パラメータのスコープ外でクロージャを定義することを可能にします。詳細については、Swift 2.2 Programming Language Guideの 末尾のクロージャ を参照してください。

Dispatch_asyncの場合、dispatch_block_t() -> Voidの型の別名であるためAPIはfunc dispatch_async(queue: dispatch_queue_t, _ block: dispatch_block_t)です。戻り値を持たない0個のパラメーターを持つクロージャー、およびblockを関数の最後のパラメーターにすることで、dispatch_asyncの外部スコープでクロージャーを定義できます。

14
Maxim Veksler

これは他の答えと同じ結果を達成するためのより良い(IMO)Swifty/Cocoaスタイルの構文です。

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

あるいは、より少ないコードとより多くの機能のために、人気のある Async Swiftライブラリ を入手することもできます。

Async.main {
    // Your code here
}
6
pejalo

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

 DispatchQueue.main.async {
      self.collectionView.reloadData()
 }
5
Sanjay Mali

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

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

これは、より良い構文のために追加できる、ちょっとしたグローバル関数です。

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()
})
1
iOS

あなたがクロージャーの中で自分自身を使っているなら、自分自身を弱めることを忘れないでください。

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