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

时间:2016-06-13 20:12:58

标签: swift google-app-engine

我有一个查询某个用户的函数,以便访问该用户的数组。我返回用户,我可以访问他们的数组。但是,调用是异步的,返回的是nil。 all上的函数有一个完成处理程序,但是,里面有一个查询调用,默认情况下该查询返回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”,以便它实际返回一些内容而不是返回任何内容。

3 个答案:

答案 0 :(得分: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,因为它更清楚地表明您正在执行异步查询。

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

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。我可能会使用自己的枚举,以避免对此代码的意图产生任何混淆。

答案 1 :(得分:0)

您可以添加中间completionHandler。这样清洁。这里只是一个例子:

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

答案 2 :(得分:0)

因为我试图将数据查询到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()
    })
}