Afnetworking post 请求的代码提取

Code extraction on Afnetworking post request

我正在尝试提取一个 post 请求,以便它可以被重新使用并尽可能保持我的代码干燥,但我有点挣扎。我开始于:

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

但是,我收到错误消息是因为响应为零,我确定这是因为没有完成处理程序。我只是不太了解如何在这种情况下实施它们,因此非常感谢朝着正确方向的推动。提前致谢!

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

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

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

因此,您需要做的不是 return 调用 manager.post 之后的响应,而是 return 从成功闭包内部响应。但是您不能简单地使用 return response 语句。您需要将 response 作为参数传递给您将传递给 [ 的回调闭包=59=]函数.

像这样:

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

而您的 class HttpRequest post 函数将是:

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[=42 中调用 fail() 回调=]块。