簡體   English   中英

在主線程上運行閉包

[英]Run closure on main thread

我創建了一個類,使開發人員更容易實現選擇器視圖。 在 UIPickerView 數據源方法中,我從閉包中返回值。 示例:

func pickerView(pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
    return pickerNumberOfRows!(component: component)
}

我對所有數據源方法使用相同的東西。 當我運行該應用程序時,它會在屏幕上顯示沒有數據的選擇器。 問題是我從閉包接收數據,而這些數據又沒有在主線程上運行。

有沒有辦法在主線程上運行該閉包並確保它返回適合數據源函數返回值類型的值? (例如,從上面的例子中,閉包將返回一個 Int)

編輯:

我知道使用 dispatch_async。 但是,就我而言,它對我沒有幫助。 假設我創建了一個在主線程上運行閉包的函數,並需要返回它看起來像這樣的值:

func closureOnMainThread()->Int{
    dispatch_async(dispatch_get_main_queue()) {
        // Run your code here
        return self.pickerNumberOfRows!(component: 0)
    }
    return 0
}

但是,上面的函數存在一個問題,即在返回調度塊內的值之前返回 0。

編輯2:使事情清楚。 我的代碼包含一個用於選擇器的自定義類和一個實現它的 UIViewController:

class CustomPickerView: NSObject, UIPickerViewDelegate, UIPickerViewDataSource {

        var pickerNumberOfRows: ((component: Int)->Int)?

        //MARK: UIPickerViewDatasource Methods
        func pickerView(pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
            return pickerNumberOfRows!(component: component)
        }

        func numberOfComponentsInPickerView(pickerView: UIPickerView) -> Int {
            return pickerNumberOfComponents!()
        }

        func pickerView(pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {print("Hello")
            return pickerRowTitle!(forRow: row, inComponent: component)
        }

        //MARK: UIPickerViewDelegate Methods
        func pickerView(pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
            pickerDidSelect!(row: row, component: component)
        }
    }

UIViewController(視圖已加載):

override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.

        let picker = CustomPickerView(parent: self)

        picker.pickerNumberOfRows = { component in
            return 10
        }
    }

請注意,我刪除了中間的輔助功能,以便您專注於主要代碼部分。

開發者可以在閉包的變量中傳入他想要的邏輯。

希望我目前理解。 在這個塊中你可以運行任何代碼,它會在主線程上執行。

dispatch_async(dispatch_get_main_queue()) { 
            // Run your code here
        }

您可以運行它以了解您是否在主線程上:

NSThread.isMainThread()

編輯

您正在尋找的是,無需返回同步響應:-> Int

您應該返回一個塊,異步響應:

func someLongProcessTaskAndReturnCompenents(completion: (components: Int)->Void){

    //Here you can do your long process task on back thread...
                    dispatch_async(dispatch_get_main_queue()) {

                        completion(self.pickerNumberOfRows!(component: 0))
                    }
         }

現在當你運行它時,響應將返回同步:

someLongProcessTaskAndReturnCompenents { (components) in
            //Your logic after response
        }

你不能像這樣將dispatch_async放在closureOnMainThread中。 這是一個異步過程,因此它將返回在 GCD 塊之外定義的 0。 所以關閉代碼中一定存在一些問題。

它必須是同步而不是異步的。

所以嘗試一些這樣的。 - 這只是一個示例代碼塊。 假設pickerNumberOfRows將在同一線程上返回一個 Int。(我使用dispatch_sync而不是dispatch_async

func closureOnMainThread()->Int{
    var x = 0;
    if (NSThread.isMainThread() == true) {
        x = self.pickerNumberOfRows!(component: 0) 
    } else {
        dispatch_sync(dispatch_get_main_queue()) {
            x = self.pickerNumberOfRows!(component: 0)
        }
    }
    return x
}

好的,問題甚至與線程/閉包無關。 問題在於在我實例化自定義選擇器的視圖控制器中使用letvar 這是一個新的視圖控制器實現:

var picker: HBPickerView?

override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view, typically from a nib.

    picker = HBPickerView(parent: self)

    picker!.presentPicker()
}

感謝所有分享答案的人。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM