如何从Swift中的void闭包返回值



我有一个函数,它查询某个用户,以便访问该用户的数组。我返回用户,我可以访问他们的数组。但是,调用是异步的,返回的内容为零。函数总体上有一个完成处理程序,但是,里面有一个查询调用,默认情况下查询返回Void。

func _getAllMatches(completionHandler: ((UIBackgroundFetchResult) -> Void)!) -> Int{
var toReturn = [GTLUserUser]()
let query = GTLQueryUser.queryForUserList()
query.userBucket = "messages-20-messagestabletes-1465782960"
service.executeQuery(query, completionHandler: {(ticket, response, error) -> Void in
if error != nil{
self._showErrorDialog(error)
return
}
else{
let userCollection = response as! GTLUserCollection
if let newUsers = userCollection.items() as? [GTLUserUser]{
toReturn = newUsers
completionHandler(UIBackgroundFetchResult.NewData)
}
}
})
return toReturn[0].likedArray.count
}

如何等待此查询返回并分配给"toReturn",以便它实际返回一些内容而不是什么都不返回。

由于它是一个异步方法,因此不能返回值,而是遵循完成处理程序模式,包括作为参数返回的数据:

func performAllMatchesQueryWithCompletionHandler(completionHandler: (UIBackgroundFetchResult, [GTLUserUser]?, ErrorType?) -> ()) {
let query = GTLQueryUser.queryForUserList()
query.userBucket = "messages-20-messagestabletes-1465782960"
service.executeQuery(query) { ticket, response, error in
guard error == nil else {
completionHandler(.failed, nil, error)
return
}
if let userCollection = response as? GTLUserCollection, let newUsers = userCollection.items() as? [GTLUserUser] {
completionHandler(.newData, newUsers, nil)
} else {
completionHandler(.noData, nil, nil)
}
}
}

我从您对UIBackgroundFetchResult的使用推断,您正在进行后台提取。如果是这样,您的performFetchWithCompletionHandler可能看起来是这样的:

func application(application: UIApplication, performFetchWithCompletionHandler completionHandler: (UIBackgroundFetchResult) -> Void) {
performAllMatchesQueryWithCompletionHandler { fetchResult, users, error in
switch fetchResult {
case .failed:
// do whatever you want if there was an error
case .noData:
// do whatever you want when there is no data
case .newData:
// do whatever you want with `users`, presumably updating your model or what have you
}
completionHandler(fetchResult)
}
}

然后,您可以从viewDidLoad或任何适合您的应用程序的地方调用此方法。

注意,我删除了方法名称上的前导下划线,因为这在Swift中不是常见的约定,但可以随心所欲地调用方法。我将_getAllMatches重命名为performAllMatchesQueryWithCompletionHandler,因为它更清楚地表明您正在执行异步查询。


在注释中,您说您不是在进行后台提取,而是在填充一个表。所以你可以做一些类似的事情:

func retrieveDataForTableView(tableView: UITableView) {
performAllMatchesQueryWithCompletionHandler { fetchResult, users, error in
switch fetchResult {
case .failed:
// do whatever you want if there was an error
case .noData:
// do whatever you want when there is no data
case .newData:
// do whatever you want with `users`, presumably updating your model or what have you
// once you've updated your model, you can reload the table:
tableView.reloadData()
}
}
}

注意,我假设这个完成处理程序在主线程上运行。如果没有,则需要dispatch_async(dispatch_get_main_queue()) { ... }更新模型并调用reloadData的代码。

就我个人而言,如果我不是真的在做后台提取,我不会倾向于将UIBackgroundFetchResult用于我的performAllMatchesQueryWithCompletionHandler。我可能会使用我自己的枚举,以避免对这段代码的意图产生任何混淆。

您可以添加一个中间完成处理程序。那样更干净。这里只是一个例子:

func application(application: UIApplication!, performFetchWithCompletionHandler completionHandler: ((UIBackgroundFetchResult) -> Void)!) {
Use_it_here() {
completionHandler(UIBackgroundFetchResult.NewData)
println("Background Fetch Complete")
}
}
func Use_it_here(completionHandler: (() -> Void)!) {
//....
//DO IT
//....
completionHandler()
}

因此,由于我试图将数据查询到表视图中,所以我的解决方案是查询数据,然后简单地重新加载数据。非常简单,不需要完成处理程序

func getMathces(){
let query = GTLQueryUser.queryForUserList()
query.userBucket = "bucketname"
service.executeQuery(query, completionHandler: {(ticket, response, error) -> Void in
if error != nil{
self._showErrorDialog(error)
return
}
else{
let userCollection = response as! GTLUserCollection
if let newUsers = userCollection.items() as? [GTLUserUser]{
for mat in newUsers[0].likedArray{
let name: String = (mat as? String)!
self.matches.append(name)
}
}
}
self.tableView.reloadData()
})
}

相关内容

最新更新