简体   繁体   English

在主线程上运行闭包

[英]Run closure on main thread

I created a class than makes implementing a picker view easier for the developer.我创建了一个类,使开发人员更容易实现选择器视图。 In the UIPickerView Datasource methods, I'm returning the values from a closure.在 UIPickerView 数据源方法中,我从闭包中返回值。 Example:示例:

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

I am using the same thing for all datasource methods.我对所有数据源方法使用相同的东西。 When I run the app, it shows the picker on screen with no data.当我运行该应用程序时,它会在屏幕上显示没有数据的选择器。 The problem is I'm receiving data from the closure which in turn are not running on the main thread.问题是我从闭包接收数据,而这些数据又没有在主线程上运行。

Is there a way to run that closure on the main thread and make sure it returns a value suitable for the datasource function return value type?有没有办法在主线程上运行该闭包并确保它返回适合数据源函数返回值类型的值? (ex, from the example above, the closure will return an Int) (例如,从上面的例子中,闭包将返回一个 Int)

EDIT:编辑:

I'm aware of using dispatch_async.我知道使用 dispatch_async。 However, in my case it will not help me.但是,就我而言,它对我没有帮助。 Let's say I created a function that runs the closure on the main thread and needs to return the value it will look something like this:假设我创建了一个在主线程上运行闭包的函数,并需要返回它看起来像这样的值:

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

However, There is a problem in the function above which is returning 0 before return the value inside the dispatch block.但是,上面的函数存在一个问题,即在返回调度块内的值之前返回 0。

Edit 2: To make things clear.编辑2:使事情清楚。 My code contains a custom class for the picker and a UIViewController implementing it:我的代码包含一个用于选择器的自定义类和一个实现它的 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 (View Did Load): 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
        }
    }

Please note I removed allot of accessory functions in between so that you focus on the main code part.请注意,我删除了中间的辅助功能,以便您专注于主要代码部分。

The developer can pass in the logic he wants in variables of closures.开发者可以在闭包的变量中传入他想要的逻辑。

Hope I undestand currently.希望我目前理解。 In this block you can run any code, and it will execute on the main Thread.在这个块中你可以运行任何代码,它会在主线程上执行。

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

You can run this to know if you are on main thread or not:您可以运行它以了解您是否在主线程上:

NSThread.isMainThread()

EDIT编辑

What you are looking for is, insted of returning a sync response : ->Int您正在寻找的是,无需返回同步响应:-> Int

You should return a block, async response:您应该返回一个块,异步响应:

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

Now when you run it, the response will return synchronized:现在当你运行它时,响应将返回同步:

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

You cannot put dispatch_async in closureOnMainThread like that.你不能像这样将dispatch_async放在closureOnMainThread中。 It is a async process so it will return 0 defined outside of GCD block.这是一个异步过程,因此它将返回在 GCD 块之外定义的 0。 SO there must be some issue inside closure code.所以关闭代码中一定存在一些问题。

Its has to be synchronouse not asynchronous.它必须是同步而不是异步的。

So try some this like this.所以尝试一些这样的。 - This is just a sample code block only. - 这只是一个示例代码块。 Assuming pickerNumberOfRows will return a Int on same thread.(I used dispatch_sync instead of dispatch_async )假设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
}

Okay, the problem was not even related to threading/closures.好的,问题甚至与线程/闭包无关。 The problem was in using let or var in the view controller where I instantiating the custom picker.问题在于在我实例化自定义选择器的视图控制器中使用letvar Here is a new view controller implementation:这是一个新的视图控制器实现:

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

Thanks for everyone who shared their answers.感谢所有分享答案的人。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM