捕获Swift中的闭包值

我的问题与其他几个人非常相似,但我无法完成工作。 我正在通过我写的帮助器类进行API调用。

首先,我尝试了一个带有返回值的标准函数,结果如预期的那样。 我厌倦了分配结果后完成了后台任务。

现在我正在使用闭包,我可以将值返回到我的视图控制器,但它仍然在闭合,我有同样的问题。 我知道我需要使用GCD来完成主队列中的任务。

这是我在我的视图控制器

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

结果是:

 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] 

我知道为什么会发生这种情况,我只是不知道如何解决它:( API调用需要是asynchronous的,那么捕获这些结果的最佳做法是什么?根据用户在表视图中select的内容,我会随后进行api调用,所以它不像我能处理closures中的所有事情

简单的解决scheme是在封闭内部执行你在print()做的任何事情。

由于您已经对主队列(主/ GUI线程)进行了dispatch_async ,所以您可以在那里完成任何处理。 推一个新的视图控制器,呈现一些模态数据,更新您当前的视图控制器等。

只要确保没有多个线程修改/访问正在显示的本地/caching数据。 特别是如果它正在被UITableViewDelegate / UITableViewDataSource实现使用,那么如果你开始变得不合时宜或者与你的返回值不一致的话,那么这个实现就会适用。

只要您可以在后台检索数据,并且主线程上需要执行的唯一处理是实例variables重新分配或某种数组附加,只需在主线程上执行该操作,即可使用检索到的数据在后端。 这不重。 如果它很重,那么你将需要更复杂的同步方法来保护你的数据。

通常情况下,模式如下所示:

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

因此,在通常刷新表视图或通知ViewController已完成操作(或已更新本地数据)的情况下,应继续进行主线程处理。

我完全同意@Craig提出的使用GCD的build议,但是由于您的问题涉及每次select行时发出的API调用请求,因此您可以执行以下操作:

  • 假设您使用tableView:didSelectRowAtIndexPath:方法来处理select,那么您可以在其中执行以下操作:

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

然后你可以观察它的属性和句柄,

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

这是看到它的另一种方式。 我希望这可以帮助你。