如何从 Swift 中的 void 闭包中返回一个值?
Posted
技术标签:
【中文标题】如何从 Swift 中的 void 闭包中返回一个值?【英文标题】:How to return a value from a void closure in Swift? 【发布时间】:2016-06-13 20:12:58 【问题描述】:我有一个函数可以查询某个用户以访问该用户的数组。我返回用户,我可以访问他们的数组。但是,调用是异步的,返回的是 nil。该函数总体上有一个完成处理程序,但是,内部有一个查询调用,默认情况下该查询返回 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”,这样它才会真正返回一些东西而不是什么都不返回。
【问题讨论】:
【参考方案1】:由于它是一个异步方法,所以不能返回值,而是遵循完成处理程序模式,包括作为参数返回的数据:
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
,因为它更清楚地表明您正在执行异步查询。
在 cmets 中,您说您不是在进行后台提取,而是在填充一个表。所以你可能会这样做:
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....? 也许我从你对UIBackgroundFetchResult
的使用中推断出太多了。当您的应用发出后台获取请求时使用它。当操作系统在您的应用程序委托上调用 performFetchWithCompletionHandler
时,就会触发这种情况。所以你不调用那个方法,而是操作系统调用。但是,如果您不进行后台提取,那么您将不会使用UIBackgroundFetchResult
。那么,您是否在进行后台提取?
是的,我是。我想要完成的是在我的视图控制器中加载一个表视图,其中包含查询返回的数字。假设我查询用户列表并返回 3。我希望我的 numberOfRowsInSection 函数返回 3。但是它正在做的是异步调用查询而不返回正确的数字。它是否在后台对我来说并不重要。我只想在每次加载视图时调用它。
我明白了。您只需在完成块中调用reloadData
。请参阅我修改后的答案。【参考方案2】:
您可以添加一个中间完成处理程序。这样更干净。这里只是一个例子:
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()
【讨论】:
【参考方案3】:因此,由于我试图将数据查询到 tableview 中,我的解决方案是查询数据,然后简单地重新加载数据。非常简单,不需要完成处理程序
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()
)
【讨论】:
以上是关于如何从 Swift 中的 void 闭包中返回一个值?的主要内容,如果未能解决你的问题,请参考以下文章