捕获Swift中的闭包值

时间:2015-07-07 21:12:50

标签: ios swift

我的问题与其他几个here非常相似,但我无法让它发挥作用。我通过我写的助手类进行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调用需要异步,那么捕获这些结果的最佳做法是什么?基于用户选择的内容表视图我将进行后续api调用,因此它不像我可以处理闭包内的所有内容

2 个答案:

答案 0 :(得分:4)

我完全同意@Craig关于使用GCD的提议,但由于您的问题涉及每次选择行时API调用的请求,您可以执行以下操作:

  • 假设您使用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
                }
             }
       } 
    }
    

然后你可以在里面观察属性并处理它:

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

这只是看待它的另一种方式。我希望这能帮到你。

答案 1 :(得分:1)

简单的解决方案是在你的print()内的中做你正在做的任何事情。

由于您已经dispatch_async到主队列(主/ GUI线程),您可以在那里完成任何处理。推送新的视图控制器,显示一些模态数据,更新当前的视图控制器等。

确保您没有多个线程修改/访问正在显示的本地/缓存数据。特别是如果它被UITableViewDelegate / UITableViewDataSource实现使用,如果你开始变得非常糟糕或与你的返回值不一致,这将会引发契合。

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

通常情况下,模式如下:

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操作已完成(或本地数据已更新),您应该继续主线程处理。