简体   繁体   English

在Swift中捕获闭包值

[英]Capturing closure values in Swift

My question is very similar to several others here but I just can't get it to work. 我的问题与这里的其他问题非常相似,但我无法解决它。 I'm making an API call via a helper class that I wrote. 我正在通过编写的帮助程序类进行API调用。

First I tried a standard function with a return value and the result was as expected. 首先,我尝试了一个带有返回值的标准函数,结果与预期的一样。 The background task completed after I tired to assign the result. 我累了要分配结果后,后台任务完成了。

Now I'm using a closure and I can get the value back into my view controller but its still stuck in the closure, I have the same problem. 现在我正在使用闭包,我可以将值返回到我的视图控制器中,但是它仍然卡在闭包中,我有同样的问题。 I know I need to use GCD to get the assignment to happen in the main queue. 我知道我需要使用GCD来使分配发生在主队列中。

this is what I have in my view controller 这就是我的视图控制器

var artists = [String]()
let api = APIController()
    api.getArtistList("foo fighters") { (thelist) -> Void in
        if let names = thelist {
            dispatch_async(dispatch_get_main_queue()) {
                artists = names
                print("in the closure: \(artists)")
            }
        }
    }

    print ("method 1 results: \(artists)")

as the results are: 结果是:

method 1 results: []
in the closure: [Foo Fighters & Brian May, UK Foo Fighters, John Fogerty with Foo Fighters, Foo Fighters, Foo Fighters feat. Norah Jones, Foo Fighters feat. Brian May, Foo Fighters vs. Beastie Boys]

I know why this is happening, I just don't know how to fix it :( The API calls need to be async, so what is the best practice for capturing these results? Based on what the user selects in the table view I'll be making subsequent api calls so its not like I can handle everything inside the closure 我知道为什么会这样,我只是不知道如何解决它:( API调用需要异步,因此捕获这些结果的最佳实践是什么?根据用户在表视图中选择的内容,将会进行后续的api调用,所以它不像我可以处理闭包内的所有内容

I completely agree with the @Craig proposal of the use of the GCD, but as your question involves the request of the API call every time you select a row, you can do the following: 我完全同意使用GCD的@Craig提议,但是由于您的问题涉及每次选择一行时对API调用的请求,因此您可以执行以下操作:

  • Let's suppose you use the tableView:didSelectRowAtIndexPath: method to handle the selection, then you can do the following inside it: 假设您使用tableView:didSelectRowAtIndexPath:方法来处理选择,然后可以在其中执行以下操作:

     func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) { // it is just a form to get the item let selectedItem = items.objectAtIndex(indexPath.row) as String api.getArtistList(selectedItem) { (thelist) -> Void in if let names = thelist { dispatch_async(dispatch_get_main_queue()) { artists = names } } } } 

And then you can observe the property and handle do you want inside it : 然后,您可以观察该属性并处理您想要在其中进行的操作:

var artists: [String] = [] {
   didSet {
      self.tableView.reloadData() // or anything you need to handle.
   }
}

It just another way to see it. 这只是另一种看待方式。 I hope this help you. 希望对您有所帮助。

The easy solution is to do whatever you're doing at your print() , inside the closure . 一个简单的解决方案是在闭包内部执行您在print()上所做的任何事情。

Since you're already dispatch_async ing to the main queue (the main/GUI thread), you can complete any processing there. 由于您已经dispatch_async同步到主队列(主/ GUI线程),因此您可以在那里完成任何处理。 Push a new view controller, present some modal data, update your current view controller, etc. 推送新的视图控制器,显示一些模式数据,更新当前的视图控制器,等等。

Just make sure that you don't have multiple threads modifying/accessing your local/cached data that is being displayed. 只要确保您没有多个线程即可修改/访问正在显示的本地/缓存数据。 Especially if it's being used by UITableViewDelegate / UITableViewDataSource implementations, which will throw fits if you start getting wishy-washy or inconsistent with your return values. 尤其是当UITableViewDelegate / UITableViewDataSource实现正在使用它时,如果您开始变得一头雾水或与您的返回值不一致,这将非常适合。

As long as you can retrieve the data in the background, and the only processing that needs to occur on the main thread is an instance variable reassignment, or some kind of array appending, just do that on the main thread, using the data you retrieved on the back end. 只要您可以在后台检索数据,并且在主线程上唯一需要进行的处理就是实例变量的重新分配或某种数组追加,那么只需使用检索到的数据在主线程上执行此操作在后端。 It's not heavy. 不重 If it is heavy, then you're going to need more sophisticated synchronization methods to protect your data. 如果它沉重的,那么你将需要更复杂的同步方法来保护您的数据。

Normally the pattern looks like: 通常,模式如下:

dispatch_async(getBackgroundQueue(), {
    var theData = getTheDataFromNetwork();
    dispatch_async(dispatch_get_main_queue() {
        self.data = theData // Update the instance variable of your ViewController
        self.tableView.reloadData() // Or some other 'reload' method
    });
})

So where you'd normally refresh a table view or notify your ViewController that the operation has completed (or that local data has been updated), you should continue your main-thread processing. 因此,在通常刷新表视图或通知ViewController操作已完成(或本地数据已更新)的地方,应继续进行主线程处理。

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

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