Gọi một phương thức trên chuỗi chính?


82

Trước hết tôi đang viết mã cho iphone. Tôi cần có thể gọi một phương thức trên chuỗi chính mà không cần sử dụng performSelectorOnMainThread. Lý do mà tôi không muốn sử dụng performSelectorOnMainThreadlà nó gây ra sự cố khi tôi đang cố gắng tạo một mô hình để thử nghiệm đơn vị.

[self performSelectorOnMainThread:@Selector(doSomething) withObject:nil];

Vấn đề là con ma của tôi biết gọi doSomethingnhưng nó không biết gọi performSelectorOnMainThread.

Vì vậy, bất kỳ giải pháp?

Câu trả lời:


272

Objective-C

dispatch_async(dispatch_get_main_queue(), ^{
    [self doSomething];
});

Nhanh

DispatchQueue.main.async {
    self.doSomething()
}

Swift kế thừa

dispatch_async(dispatch_get_main_queue()) {
    self.doSomething()
}

Bạn vừa tạo nên ngày của tôi với mã 3 nhanh chóng. Cảm ơn!
Felipe Balduino

Thực hành tốt là không sử dụng tự trực tiếp vào khối. thay vào đó sử dụng tham chiếu yếu của nó.
Jageen

2

Có một câu nói trong phần mềm rằng việc thêm một lớp chuyển hướng sẽ khắc phục được hầu hết mọi thứ.

Đặt phương thức doSomething là một trình bao hướng dẫn chỉ thực hiện một hàm PerformSelectorOnMainThread để gọi phương thức thực sự_doSomething để thực hiện một công việc gì đó thực sự. Hoặc, nếu bạn không muốn thay đổi phương thức doSomething của mình, hãy yêu cầu đơn vị thử nghiệm gọi phương thức doSomething_redirect_shell để thực hiện điều gì đó tương tự.


1

Đây là một cách tốt hơn để làm điều này trong Swift:

runThisInMainThread { () -> Void in
    // Run your code
    self.doSomething()
}

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

Nó được bao gồm như một chức năng tiêu chuẩn trong repo của tôi, hãy kiểm tra: https://github.com/goktugyil/EZSwiftExtensions


Điều này không tốt hơn theo bất kỳ cách nào, bạn đã tạo một hàm không làm gì khác ngoài việc gọi một hàm khác. bởi cách mà cú pháp nhanh chóng có thể được đơn giản hóa hơn nữa "() -> Void trong" là không cần thiết
aryaxt

Con người có thể đọc / ghi được nhiều hơn. Có tính năng tự động điền thêm vào "() -> Bỏ trống trong". Vẫn có cách nào để vô hiệu hóa hành vi tự động hoàn thành này trong void> void close?
Esqarrouth

tên phương thức bạn có có thể gây hiểu lầm, có vẻ như khối sẽ được thực thi ngay trên luồng chính, nhưng điều đó không đúng. dispatch_async trên hàng đợi chính thêm khối mã để các runloop tới, hành vi quan trọng này được giấu đằng sau những phương pháp đó được gọi là "runThisInMainThread
aryaxt

1
đây là hành vi mong đợi, disp_async thêm mã vào cuối hàng đợi. Nếu bạn muốn nó được gọi ngay lập tức, thay vào đó bạn nên thực hiện điều khiển_sync. Nếu bạn thực hiện điều phối_sync trên hàng đợi cho luồng mà bạn đã ở trong đó sẽ gây ra khóa luồng. trong ví dụ của bạn, thứ tự các bản in là "a", "c", "b". a và c đang được thực thi trong 1 runloop vì chúng nằm trong cùng một phạm vi. b sẽ được thêm vào cuối hàng đợi nên nó được gọi là đôi khi sau khi các mặt hàng khác hiện có trong hàng đợi được hoàn thành
aryaxt

1
@Esqarrouth - bạn có CHẮC CHẮN dispatch_asyncmã bị chặn của mình sau khi gọi đến nó không? Toàn bộ điểm của việc sử dụng asyncthay vì synclà KHÔNG chặn những gì tiếp theo. (Tất nhiên, blockmã SẼ chặn bất kỳ thứ gì khác trên chuỗi chính , vì điểm của mã yêu cầu là thực thi trên chuỗi chính. Nếu bạn muốn chạy mã nền, thì bạn sẽ yêu cầu một hàng đợi khác, không dispatch_get_main_queue.)
ToolmakerSteve

1

Và bây giờ trong Swift 3:

DispatchQueue.main.async{
   self.doSomething()
}

-4
// Draw Line
    func drawPath(from polyStr: String){
        DispatchQueue.main.async {
            let path = GMSPath(fromEncodedPath: polyStr)
            let polyline = GMSPolyline(path: path)
            polyline.strokeWidth = 3.0
            polyline.strokeColor = #colorLiteral(red: 0.05098039216, green: 0.5764705882, blue: 0.2784313725, alpha: 1)
            polyline.map = self.mapVu // Google MapView
        }

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