Afnetworking post请求的代码提取

时间:2017-02-09 22:03:47

标签: ios swift afnetworking

我正在尝试提取一个帖子请求,以便可以重复使用并尽可能让我的代码保持干净,但是我有点挣扎。我开始时:

func createAccount() {
    let manager = AFHTTPSessionManager()
    let dob = self.dobTextField.text!.components(separatedBy: "/")
    let URL = "https://splitterstripeservertest.herokuapp.com/account"
    let params = [
                "first_name": firstNameTextField.text!.trim(),
                "last_name": lastNameTextField.text!.trim(),
                "line1": addressLine1TextField.text!.trim(),
                "city": cityTextField.text!.trim(),
                "postal_code": postCodeTextField.text!.trim(),
                "email": emailTextField.text!.trim(),
                "day": UInt(dob[0])! as UInt,
                "month": UInt(dob[1])! as UInt,
                "year": UInt(dob[2])! as UInt] as [String : Any]

    manager.requestSerializer = AFHTTPRequestSerializer()
    manager.responseSerializer = AFHTTPResponseSerializer()
    manager.post(URL, parameters: params, progress: nil, success: {(_ task: URLSessionDataTask, _ responseObject: Any) -> Void in
        do {
            let response = try JSONSerialization.jsonObject(with: responseObject as! Data, options: .mutableContainers) as? [String: Any]
            self.stripeAccountID = response?["id"] as! String
            self.stopAnimating()
            self.goToFinalStage()
        } catch {
            print("Serialising new account json object went wrong.")
            self.stopAnimating()
        }
    }, failure: { (operation, error) -> Void in
        self.handleError(error as NSError)
        self.stopAnimating()
    })
}

并归结为:

func createAccount() {

    let request = HttpRequest()
    let response = request.post(params: setParams(), URLExtension: "account")

    if (response != nil) {
        successfulRequest(response: response!)
    } else {
        failedRequest(response: response!)
    }
}

func successfulRequest(response: AnyObject) {
    self.stripeAccountID = response["id"] as! String
    createMainBillSplitter()
    self.stopAnimating()
    performSegue(withIdentifier: "segueToFinalRegistrationViewController", sender: self)
}

func failedRequest(response: AnyObject) {
    self.stopAnimating()
    self.handleError(response["failed"] as! NSError)
}

HTTPRequest是:

class HttpRequest {

    let manager = AFHTTPSessionManager()
    let baseURL = "https://splitterstripeservertest.herokuapp.com/account"

    func post(params: [String: Any], URLExtension: String) -> AnyObject? {

        let URL = baseURL + URLExtension
        var response = [String: Any]()

        manager.requestSerializer = AFHTTPRequestSerializer()
        manager.responseSerializer = AFHTTPResponseSerializer()
        manager.post(URL, parameters: params, progress: nil, success: {(_ task: URLSessionDataTask, _ responseObject: Any) -> Void in
            do {
                response = try JSONSerialization.jsonObject(with: responseObject as! Data, options: .mutableContainers) as! [String: Any]

            } catch {
                print("Serialising new account json object went wrong.")
            }
        }, failure: { (operation, error) -> Void in
            response = ["failed": error]
        })
        return response as AnyObject?
    }

    func handleError(_ error: NSError) -> UIAlertController {
        let alert = UIAlertController(title: "Please Try Again", message: error.localizedDescription, preferredStyle: .alert)
        alert.addAction(UIAlertAction(title: "OK", style: .cancel, handler: nil))
        return alert
    }
}

但是,我收到错误是因为响应为零,我确信这是因为没有完成处理程序。我只是不明白如何在这种情况下实施它们,所以真的很感激推动正确的方向。提前谢谢!

1 个答案:

答案 0 :(得分:1)

您对同步与异步操作感到困惑。

manager.post 功能会创建您的http请求,并会在 成功 关闭时调用完成。但由于该函数是作为异步操作实现的,因此在执行该http请求时,您的代码不会停止。因此,您的代码将继续执行,在您的情况下,下一行是您返回 响应 ,这基本上是您的空字符串数组。

func post(params: [String: Any], URLExtension: String) -> AnyObject? {

   let URL = baseURL + URLExtension
   var response = [String: Any]()

   manager.requestSerializer = AFHTTPRequestSerializer()
   manager.responseSerializer = AFHTTPResponseSerializer()
   manager.post(URL, parameters: params, progress: nil, success: {(_ task: URLSessionDataTask, _ responseObject: Any) -> Void in
       // this closure is executed only when the request is completed
       do {
        response = try JSONSerialization.jsonObject(with: responseObject as! Data, options: .mutableContainers) as! [String: Any]

       } catch {
           print("Serialising new account json object went wrong.")
       }
   }, failure: { (operation, error) -> Void in
       response = ["failed": error]
   })

   return response as AnyObject?  // <<-- this line is executed right after the manager.post line above, but the success closure was not called yet because the request is still going on.
}

因此,您需要做的是在调用manager.post之后不立即返回响应,而是从成功闭包内返回它。但您不能简单地使用 返回响应 语句。您需要将 响应 作为参数传递给您将传递给 request.post 的回调关闭功能

这样的事情:

    func createAccount() {

       let request = HttpRequest()
       let response = request.post(params: setParams(), 
                   URLExtension: "account", 
                   success: {response in
                      // enter here the code to be executed when request is completed.
                        successfulRequest(response: response)
                   },
                   fail: {response in
                        failedRequest(response: response)
                   },)
   }

你的HttpRequest后期函数将是:

func post(params: [String: Any], URLExtension: String, success:([String: Any] -> Void), fail:([String: Any] -> Void)) -> AnyObject? {

    let URL = baseURL + URLExtension

    manager.requestSerializer = AFHTTPRequestSerializer()
    manager.responseSerializer = AFHTTPResponseSerializer()
    manager.post(URL, parameters: params, progress: nil, success: {(_ task: URLSessionDataTask, _ responseObject: Any) -> Void in
        do {
            response = try JSONSerialization.jsonObject(with: responseObject as! Data, options: .mutableContainers) as! [String: Any]
            success(response)

        } catch {
            print("Serialising new account json object went wrong.")
        }
    }, failure: { (operation, error) -> Void in
        response = ["failed": error]
        fail(response)
    })
}

PS:您的代码假设它始终能够解码JSON响应。虽然您使用的是do / catch,但如果由于某种原因JSON解码失败,则不会将响应发送回您的调用函数。所以,该应用程序将被卡住。我建议您在 catch 块中调用 fail() 回调。