捕获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. } }
这是看到它的另一种方式。 我希望这可以帮助你。