Trong Swift làm thế nào để gọi phương thức với các tham số trên luồng chính GCD?


192

Trong ứng dụng của mình, tôi có một chức năng tạo NSRURLSession và gửi NSURLRequest bằng cách sử dụng

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

Trong khối hoàn thành cho nhiệm vụ này, tôi cần thực hiện một số tính toán có thêm UIImage vào trình điều khiển khung nhìn cuộc gọi. Tôi có một chức năng được gọi là

func displayQRCode(receiveAddr, withAmountInBTC:amountBTC)

đó là tính toán thêm UIImage. Nếu tôi cố chạy mã thêm chế độ xem bên trong khối hoàn thành, Xcode sẽ đưa ra lỗi nói rằng tôi không thể sử dụng công cụ bố trí trong khi đang xử lý nền. Vì vậy, tôi đã tìm thấy một số mã trên SO cố gắng xếp hàng một phương thức trên luồng chính:

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

Tuy nhiên, tôi không biết cách thêm các tham số "receiveAddr" và "lượngBTC" vào lệnh gọi hàm này. Làm thế nào tôi có thể làm điều này hoặc ai đó có thể đề xuất một cách tối ưu để thêm một cuộc gọi phương thức vào hàng đợi chính của ứng dụng?

Câu trả lời:


496

Các phiên bản hiện đại của Swift sử dụng DispatchQueue.main.asyncđể gửi đến luồng chính:

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

Để gửi sau trên hàng đợi chính, sử dụng:

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

Các phiên bản cũ hơn của Swift được sử dụng:

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

Mặc dù bạn đúng rằng đề xuất của bạn hoạt động, tôi nghĩ rằng câu trả lời của tôi tốt hơn một chút vì nó không thực hiện cuộc gọi tới UIApplication. SharedApplication, điều này không bình thường và có thể loại bỏ những người đọc mã khác của tôi. Phạm vi câu trả lời của tôi bị giới hạn trong các đối tượng quan trọng, trong khi phạm vi của bạn mang đến các đối tượng phụ trợ yêu cầu tôi đọc thêm tài liệu để tìm hiểu chính xác những gì tôi đang làm. Và tôi đã chỉnh sửa câu hỏi ban đầu của mình để chứa lệnh gọi hàm chính xác. Tôi đã nghĩ displayQRCode không đủ cụ thể nhưng với ý kiến ​​của chúng tôi thì bây giờ nó đã như vậy. Cảm ơn đã chỉ ra rằng.
alm

84

Phiên bản Swift 3+ & Swift 4:

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

Swift 3 và Xcode 9.2:

dispatch_async_on_main_queue {
    print("Hello")
}

15

Swift 2

Sử dụng Trailing Closures trở thành:

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

Trailing Closures là đường cú pháp Swift cho phép xác định bao đóng bên ngoài phạm vi tham số hàm. Để biết thêm thông tin, xem Trailing Closures trong Swift 2.2 Hướng dẫn ngôn ngữ lập trình.

Trong trường hợp dispatch_async API là func dispatch_async(queue: dispatch_queue_t, _ block: dispatch_block_t)từ dispatch_block_tlà loại bí danh cho () -> Void- Một đóng cửa tiếp nhận các thông số 0 và không có giá trị trả về, và khối là tham số cuối cùng của hàm chúng ta có thể xác định việc đóng cửa trong phạm vi bên ngoài của dispatch_async.


1
đó chính xác là 3 dòng tôi đang tìm kiếm ... bây giờ bạn có thể ngừng đọc suy nghĩ của tôi
Laszlo

8

Tải lại bộ sưu tập Xem trên Chủ đề chính

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

7

Đây là cú pháp kiểu Swifty / Ca cao đẹp hơn (IMO) để đạt được kết quả tương tự như các câu trả lời khác:

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

Hoặc bạn có thể lấy thư viện Async Swift phổ biến để có ít mã hơn và nhiều chức năng hơn:

Async.main {
    // Your code here
}

phương thức được đổi tên thànhOperationQueue.main.addOperation({ }
Frostmourne

3

Cách thích hợp để làm điều này là sử dụng Clark_async trong main_queue, như tôi đã làm trong đoạn mã sau

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

2

Đây là một chức năng toàn cầu nhỏ mà bạn có thể thêm cho một cú pháp đẹp hơn:

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

Và cách sử dụng

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

Đừng quên làm yếu bản thân nếu bạn đang sử dụng bản thân trong phần đóng cửa.

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

1
Bạn có thể vui lòng giải thích tại sao chúng ta nên làm điều này?
Jackspicer

Đó là bởi vì nó có thể tạo ra các chu kỳ bộ nhớ - tức là tôi có một tài liệu tham khảo mạnh mẽ về một cái gì đó và nó có một tài liệu tham khảo mạnh mẽ cho tôi. Có nghĩa là không ai trong chúng ta có thể rời khỏi đống ký ức.
jackofallcode
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.