Di Swift cara memanggil metode dengan parameter pada utas utama GCD?

192

Dalam aplikasi saya, saya memiliki fungsi yang membuat NSRURLSession dan mengirimkan NSURLRequest menggunakan

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

Di blok penyelesaian untuk tugas ini, saya perlu melakukan beberapa perhitungan yang menambahkan UIImage ke viewcontroller panggilan. Saya memiliki fungsi yang dipanggil

func displayQRCode(receiveAddr, withAmountInBTC:amountBTC)

yang melakukan perhitungan penambahan UIImage. Jika saya mencoba menjalankan kode tambah-tampilan di dalam blok penyelesaian, Xcode melempar kesalahan yang mengatakan bahwa saya tidak dapat menggunakan mesin tata letak saat dalam proses latar belakang. Jadi saya menemukan beberapa kode pada SO yang mencoba mengantri metode pada utas utama:

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

Namun, saya tidak tahu bagaimana cara menambahkan parameter "acceptAddr" dan "numberBTC" ke pemanggilan fungsi ini. Bagaimana saya melakukan ini, atau bisakah seseorang menyarankan cara optimal untuk menambahkan pemanggilan metode ke antrian utama aplikasi?

almel
sumber

Jawaban:

496

Versi modern dari Swift digunakan DispatchQueue.main.asyncuntuk mengirim ke utas utama:

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

Untuk mengirim setelah pada antrian utama, gunakan:

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

Versi Swift yang lebih lama digunakan:

dispatch_async(dispatch_get_main_queue(), {
  let delegateObj = UIApplication.sharedApplication().delegate as YourAppDelegateClass
  delegateObj.addUIImage("yourstring")
})
codester
sumber
Meskipun Anda benar bahwa saran Anda berfungsi, saya pikir jawaban saya sedikit lebih baik karena tidak membuat panggilan ke UIApplication.shareplatformApplication, yang tidak biasa dan mungkin membuang pembaca kode saya yang lain. Cakupan jawaban saya terbatas pada objek-objek yang penting, sedangkan milik Anda membawa objek-objek pendukung yang mengharuskan saya membaca lebih banyak dokumen untuk mempelajari apa yang saya lakukan. Dan saya telah mengedit pertanyaan awal saya untuk memuat pemanggilan fungsi yang benar. Saya pikir displayQRCode tidak cukup spesifik tetapi dengan komentar kami sekarang. Terima kasih telah menunjukkannya.
almel
84

Versi Swift 3+ & Swift 4:

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

Swift 3 dan Xcode 9.2:

dispatch_async_on_main_queue {
    print("Hello")
}
DazChong
sumber
15

Cepat 2

Menggunakan Trailing Closures ini menjadi:

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

Trailing Closures adalah gula sintaksis Swift yang memungkinkan pendefinisian penutupan di luar lingkup parameter fungsi. Untuk informasi lebih lanjut lihat Trailing Closures in Swift 2.2 Panduan Bahasa Pemrograman.

Dalam hal dispatch_async API adalah func dispatch_async(queue: dispatch_queue_t, _ block: dispatch_block_t)karena dispatch_block_ttipe alias untuk () -> Void- Sebuah penutupan yang menerima 0 parameter dan tidak memiliki nilai kembali, dan blok menjadi parameter terakhir dari fungsi kita dapat mendefinisikan penutupan di lingkup luar dispatch_async.

Maxim Veksler
sumber
1
itulah tepatnya 3 baris yang saya cari ... sekarang Anda bisa berhenti membaca pikiranku
Laszlo
8

Muat ulang collectionView di Main Thread

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

Berikut sintaks gaya Swifty / Cocoa yang lebih bagus (IMO) untuk mencapai hasil yang sama dengan jawaban lainnya:

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

Atau Anda bisa mengambil pustaka Async Swift yang populer dengan kode yang lebih sedikit dan lebih banyak fungsi:

Async.main {
    // Your code here
}
pejalo
sumber
metode diubah namanya menjadiOperationQueue.main.addOperation({ }
Frostmourne
3

Cara yang tepat untuk melakukan ini adalah dengan menggunakan dispatch_async di main_queue, seperti yang saya lakukan pada kode berikut

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

Inilah fungsi global kecil yang menyenangkan yang dapat Anda tambahkan untuk sintaksis yang lebih bagus:

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

Dan penggunaan

dispatch_on_main {
    // Do some UI stuff
}
Mateusz Grzegorzek
sumber
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()
})
iOS
sumber
2

Jangan lupa untuk melemahkan diri sendiri jika Anda menggunakan diri di dalam penutupan.

dispatch_async(dispatch_get_main_queue(),{ [weak self] () -> () in
    if let strongSelf = self {
        self?.doSomething()
    }
})
villy393
sumber
1
Bisakah Anda jelaskan mengapa kami harus melakukan ini?
Jackspicer
Itu karena dapat membuat siklus memori - yaitu saya memiliki referensi yang kuat untuk sesuatu dan memiliki referensi yang kuat kepada saya. Berarti tidak ada di antara kita yang bisa meninggalkan tumpukan memori.
jackofallcode