Alamofire 自定义响应从 Alamofire v1.3 迁移到 3.0(和 Swift 2 语法)

Posted

技术标签:

【中文标题】Alamofire 自定义响应从 Alamofire v1.3 迁移到 3.0(和 Swift 2 语法)【英文标题】:Alamofire custom reponse migration from Alamofire v1.3 to 3.0 (and Swift 2 syntax) 【发布时间】:2015-11-17 15:17:26 【问题描述】:

我正在将使用 Alamofire 1.3 的项目从 Swift 1.1 转换为 Swift 2.0。 因为这个版本的 Alamofire 与 Swift 2.0 不兼容,所以我切换到了 Alamofire 的最新版本(3.1.x)。

但是这破坏了代码,我现在收到错误消息

“不能调用非函数类型'NSHTTPURLResponse'的值?'”

这是由于我创建自定义“responseShop”Alamofire.Request 的扩展。

如何才能将此 Alamofire.Request 扩展正确转换为 Alamofire 3.x/Swift 2.0 语法?

extension Alamofire.Request 
    func responseShop(options: NSJSONReadingOptions = .AllowFragments, var errorHandler:ProtocolWebServiceErrorHandler?, completionHandler: (ShopCallResult?, WebServiceErrorCode) -> Void ) -> Self 
        objc_sync_enter(communicationLockObj)
        return response(serializer: Request.JSONResponseSerializer(options: options), completionHandler: 
            (request, response, JSON, error) in
            log.verbose("\(JSON)")
            //network error?
            if let error = error 
                //is it cancelled?
                if error.code == -999 
                    dispatch_async(dispatch_get_main_queue()) 
                        //call handler with cancelled code
                        completionHandler(nil, WebServiceErrorCode.requestCancelled)
                    
                    objc_sync_exit(communicationLockObj)
                    return
                

                dispatch_async(dispatch_get_main_queue()) 
                    errorHandler?.handleWebServiceError(WebServiceErrorCode.connectError, errorText : error.localizedDescription, request: request, json: JSON)
                    //call and supply org error
                    completionHandler(nil, WebServiceErrorCode.connectError)
                
                objc_sync_exit(communicationLockObj)
                return
            
            if JSON == nil 
                dispatch_async(dispatch_get_main_queue()) 
                    errorHandler?.handleWebServiceError(WebServiceErrorCode.jsonNil, errorText: nil, request: request, json: JSON)
                    //call and supply org error
                    completionHandler(nil, WebServiceErrorCode.jsonNil)
                
                objc_sync_exit(communicationLockObj)
                return
            
            //api return error?
            let callResult = ShopCallResult(json: JSON!)
            if callResult.statusCode.failed 
                dispatch_async(dispatch_get_main_queue()) 
                    errorHandler?.handleWebServiceError(callResult.statusCode, errorText: callResult.statusCode.localizedText, request: request, json: JSON)
                    completionHandler(callResult, callResult.statusCode)
                
                objc_sync_exit(communicationLockObj)
                return
            
            //no error
            dispatch_async(dispatch_get_main_queue()) 
                completionHandler(callResult, WebServiceErrorCode.OK)
            
            objc_sync_exit(communicationLockObj)
        )
        return self
    

【问题讨论】:

您不再需要指定 Json 序列化程序。尝试用responseJSON response in debugPrint(response) 替换response 看看这里的例子github.com/Alamofire/Alamofire/blob/master/Documentation/… 【参考方案1】:

根据@ProblemSolver 的反馈,我设法转换了代码,现在看起来像这样:

extension Alamofire.Request 

    func responseShop(queue: dispatch_queue_t? = nil, options: NSJSONReadingOptions = .AllowFragments, errorHandler:ProtocolWebServiceErrorHandler?, completionHandler: (ShopCallResult?, WebServiceErrorCode) -> Void ) -> Self 
        //enter thread protected area...
        objc_sync_enter(communicationLockObj)

        return responseJSON() 
            response in
            switch response.result 
            case .Success(let JSON):
                //log json in verbose mode
                log.verbose("\(JSON)")
                //parse the returned json
                let callResult = ShopCallResult(json: JSON)
                //is it failed?
                if callResult.statusCode.failed 
                    //call supplied error handler on the main thread
                    dispatch_async(dispatch_get_main_queue()) 
                        errorHandler?.handleWebServiceError(callResult.statusCode, errorText: callResult.statusCode.localizedText, request: self.request!, json: JSON)
                        completionHandler(callResult, callResult.statusCode)
                    
                    //release the lock
                    objc_sync_exit(communicationLockObj)
                    //processing done!
                    return
                
                //no error call handler on main thread
                dispatch_async(dispatch_get_main_queue()) 
                    completionHandler(callResult, WebServiceErrorCode.OK)
                
                //release the lock
                objc_sync_exit(communicationLockObj)

            case .Failure(let error):
                //WARNING: cancelled is still error code 999?
                //is it cancelled?
                if error.code == -999 
                    //just call the completion handler
                    dispatch_async(dispatch_get_main_queue()) 
                        //call handler with cancelled code
                        completionHandler(nil, WebServiceErrorCode.requestCancelled)
                    
                    //release the lock
                    objc_sync_exit(communicationLockObj)
                    //stop furhter processing
                    return
                
                //error with the json?
                if error.code == Alamofire.Error.Code.JSONSerializationFailed .rawValue 
                    //call the error handler
                    dispatch_async(dispatch_get_main_queue()) 
                        errorHandler?.handleWebServiceError(WebServiceErrorCode.jsonNil, errorText: nil, request: self.request!, json: nil)
                        //call and supply org error
                        completionHandler(nil, WebServiceErrorCode.jsonNil)
                    
                    //release the lock
                    objc_sync_exit(communicationLockObj)
                    //stop further processing
                    return
                
                //must be some other kind of network error
                dispatch_async(dispatch_get_main_queue()) 
                    log.error("\(error)")
                    //so call the error handler
                    errorHandler?.handleWebServiceError(WebServiceErrorCode.connectError, errorText : error.localizedDescription, request: self.request!, json: nil)
                    //call and supply org error
                    completionHandler(nil, WebServiceErrorCode.connectError)
                
                //release the lock
                objc_sync_exit(communicationLockObj)
            
        
    

【讨论】:

我不太确定锁定的原因,但您可以使用 Swift 2 中的 defer 语法进行 objc_sync_exit 调用。而不是重复 5 次。 锁定背后的想法是一次只能激活一个 Web 服务调用(它们应该被序列化......)。老实说,不确定锁定是否能实现这一点......因为我们已经在使用队列

以上是关于Alamofire 自定义响应从 Alamofire v1.3 迁移到 3.0(和 Swift 2 语法)的主要内容,如果未能解决你的问题,请参考以下文章

自定义序列化在 Alamofire 4.0 中发现不正确的“响应”

swift 具有Argo和自定义错误类型的Generic Alamofire响应序列化程序

Alamofire.request 不与自定义对象映射

Alamofire - 如何从 AFError 获取 API 错误

Alamofire+Combine:如何从 AFError 中获取自定义错误类型

swift上的Alamofire返回状态代码问题