如何从Swift中的void闭包返回值? [英] How to return a value from a void closure in Swift?

查看:116
本文介绍了如何从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) - >如果错误!= nil {
self._showErrorDialog(错误)
return
} $ b, $ b else {
let userCollection = response as!GTLUserCollection
if newUsers = userCollection.items()as?[GTLUserUser] {
toReturn = newUsers
completionHandler(UIBackgroundFetchResult.NewData )

}
}
})

return toReturn [0] .likedArray.count
}

如何等待此查询返回并分配给toReturn,以便它实际返回某些内容而不返回任何内容。 / p>

解决方案

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

  func performAllMatchesQueryWithCompletionHandler(completionHandler:(UIBackgroundFetchResult,[GTLUserUser] ?, ErrorType?) - > ()){
let query = GTLQueryUser.queryForUserList()
query.userBucket =messages-20-messagestabletes-1465782960
service.executeQuery(query){ticket,response,error in
警卫错误== nil else {
completionHandler(.Failed,nil,error)
return
}

如果让userCollection = response as? GTLUserCollection,让newUsers = userCollection.items()为? [GTLUserUser] {
completionHandler(.NewData,newUsers,nil)
} else {
completionHandler(.NoData,nil,nil)
}
}
}

我使用 UIBackgroundFetchResult ,你正在做一个背景获取。如果是这样,你的 performFetchWithCompletionHandler 可能如下所示:

  func application应用程序:UIApplication,performFetchWithCompletionHandler completionHandler:(UIBackgroundFetchResult) - > Void){
performAllMatchesQueryWithCompletionHandler {fetchResult,用户,
中的错误switch fetchResult {
case .Failed:
// do无论你想要什么,如果有错误

case .NoData:
//在没有数据时做任何你想做的事

case .NewData:
//使用`用户`做任何你想要的,大概更新你的模型或者你有什么

$ b completionHandler(fetchResult)
}
}

然后,您可以从 viewDidLoad 或任何适当的位置调用此方法为您的应用程序。

请注意,我删除了方法名称的前导下划线,因为这不是一个公司在Swift中使用mmon约定,但可以随意调用你的方法。我将 _getAllMatches 重命名为 performAllMatchesQueryWithCompletionHandler ,因为它更清楚地表明您正在执行异步查询。 p>




在评论中,你说你不是在进行后台获取,而是在填充表格。所以你可能会这样做:

  func retrieveDataForTableView(tableView:UITableView){
performAllMatchesQueryWithCompletionHandler {fetchResult,users,error in
switch fetchResult {
case .Failed:
//做任何你想做的事情,如果出现错误

case .NoData:
// do无论你想要什么时,当没有数据

案例.NewData:
//用`用户`做任何你想要的,大概更新你的模型或者你有什么

//一旦你更新了模型,你可以重新加载表:

tableView.reloadData()}
}
}
dispatch_async(dispatch_get_main_queue()){...}
更新模型并调用 reloadData

个人而言,我不会倾向于使用 UIBackgroundFetchResult 来为我的 performAllMatchesQueryWithCompletionHandler 如果我没有真正做后台提取。我可能会使用我自己的枚举,以避免对此代码的意图产生任何混淆。


I have a function that queries a certain user in order to access an array of that user. I returns the user and I can access their array. However, the call is asynchronous and what is being returned is nil. The function over all has a completion handler, however, inside there is a query call and by default that query returns 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
}

How do I wait for this query to return and assign to "toReturn" so that it will actually return something instead of returning nothing.

解决方案

Since it's an asynchronous method, you cannot return the value, but instead follow the completion handler pattern, including the data returned as a parameter:

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

I infer from your use of UIBackgroundFetchResult, that you're doing a background fetch. If so, your performFetchWithCompletionHandler might look like so:

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

You could then call this method from viewDidLoad or wherever appropriate for your app.

Note, I removed the leading underscore on the method names, as that's not a common convention in Swift, but call your methods whatever you want. And I renamed _getAllMatches to performAllMatchesQueryWithCompletionHandler, as it makes it more clear that you're performing an asynchronous query.


In comments, you say that you're not doing background fetch, but rather are populating a table. So you might do something like:

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

Note, I've assumed that this completion handler is running on the main thread. If not, you'd want to dispatch_async(dispatch_get_main_queue()) { ... } the code that updates the model and calls reloadData.

Personally, I wouldn't be inclined to use UIBackgroundFetchResult for my performAllMatchesQueryWithCompletionHandler if I wasn't really doing background fetch. I'd probably use my own enumeration for that, to avoid any confusion regarding the intent of this code.

这篇关于如何从Swift中的void闭包返回值?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆