从 PromiseKit/Alamofire 返回一个 Promise

Posted

技术标签:

【中文标题】从 PromiseKit/Alamofire 返回一个 Promise【英文标题】:Returning a Promise from PromiseKit/Alamofire 【发布时间】:2016-11-16 17:34:53 【问题描述】:

我正在尝试做这件看似微不足道的事情:

static func list() -> Promise<[Activity]> 
    let endpoint = "\(self.baseUrl)/v1/activities"

    return Promise  fulfill, reject in
        self.fetchHeaders  (headers) in
            return Alamofire.request(
                endpoint,
                method: .get,
                parameters: nil,
                encoding: JSONEncoding.default,
                headers: headers
            ).validate().responseJSON().then()  response in
                guard let json = response as? JSON else 
                    reject(ActivityError.parse("Malformed JSON"))
                

                guard let jsonActivities = json["activities"] as? [JSON] else 
                    reject(ActivityError.parse("Missing field"))
                

                var activities: [Activity] = []

                for jsonActivity in jsonActivities 
                    guard let activity = Activity(json: jsonActivity) else 
                        reject(ActivityError.parse("Unable to parse an Activity object"))
                    

                    activities.append(activity)
                

                fulfill(activities)
            .catch  error in
                reject(ActivityError.network("HTTP response failure"))
            
        
    

但是,编译器(理所当然地)抱怨:

'guard' body 可能不会掉下来,考虑使用 'return' 或 'break' 退出范围

我知道我需要在此处返回一个 Promise。我只是不知道在 reject() 和 fulfill() 调用下面到底要放什么。

【问题讨论】:

【参考方案1】:

rejectfulfill 调用没有任何问题。问题是,在您的 guard 语句中 reject 之后,您还必须 return 退出关闭:

guard let json = response as? JSON else 
    reject(ActivityError.parse("Malformed JSON"))
    return


guard let jsonActivities = json["activities"] as? [JSON] else 
    reject(ActivityError.parse("Missing field"))
    return

关键是你不想将这个方法返回的承诺(后来被fulfillreject满足)与在这个闭包中你必须立即退出的事实混为一谈在guard 子句中带有return 的闭包。


我无法用您的代码重现此问题(因为您没有提供MCVE 并且这里有一些我无法解决的参考资料)。但这里是您的代码的简化版本,说明了guard 的使用:

所以,如果不使用 PromiseKit/Alamofire,你可以这样做:

func list() -> Promise<[String: Any]> 
    return Promise  fulfill, reject in
        Alamofire.request(url)
            .validate()
            .responseJSON  response in
                switch response.result 
                case .success(let json):
                    guard let dictionary = json as? [String: Any] else 
                        reject(ActivityError.malformed("not a dictionary"))
                        return
                    
                    fulfill(dictionary)
                case .failure(let error):
                    reject(error)
                
        
    

如您所见,您返回的是 Promise,但在 Alamofire 闭包中,您只是退出了 guard 语句。


如果您使用 PromiseKit/Alamofire 并调用 then,您可能想要创建一个可以返回的 Promise,例如:

func list() -> Promise<String> 
    return Alamofire.request(endPoint)
        .validate()
        .responseJSON()
        .then  value in
            return Promise  fulfill, reject in
                guard let dictionary = value as? [String: Any], let name = dictionary["name"] as? String else 
                    reject(ActivityError.malformed("not dictionary"))
                    return
                

                fulfill(name)
            
    

或者如果这太麻烦了,你可以把value的解析拉出来:

func list() -> Promise<String> 
    return Alamofire.request(endPoint)
        .validate()
        .responseJSON()
        .then  value in
            self.parse(value)
    


func parse(_ value: Any) -> Promise<String> 
    return Promise  fulfill, reject in
        guard let dictionary = value as? [String: Any], let name = dictionary["name"] as? String else 
            reject(ActivityError.malformed("not dictionary"))
            return
        

        fulfill(name)
    

但是,无论哪种方式,即使使用 PromiseKit/Alamofire,您仍然只是在 guard 子句中使用 return

【讨论】:

那不行,我实际上需要在那里返回一个 Promise。返回 void 不会建立。 我试过了。请注意,我正在使用 PromiseKit/Alamofire,并且 HTTP 响应以 promise then() 的形式返回,它不能只返回 Void。它需要返回一个 Promise。 我已经用更多的例子更新了我的答案(这些例子已经过测试并且可以工作)。我无法帮助您诊断您的代码,因为我不知道其中一些例程的作用。如果您仍有问题,请通过complete, simple, standalone, reproducible example 更新您的问题。

以上是关于从 PromiseKit/Alamofire 返回一个 Promise的主要内容,如果未能解决你的问题,请参考以下文章

从函数返回“本地”字符*与从函数返回“本地”int*之间的区别[重复]

如何从异步调用返回响应

如何从异步调用返回响应

如何从异步调用返回响应

如何从异步调用返回响应

如何从异步调用返回响应