我正在尝试提取一个帖子请求,以便可以重复使用并尽可能让我的代码保持干净,但是我有点挣扎。我开始时:
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
}
}
但是,我收到错误是因为响应为零,我确信这是因为没有完成处理程序。我只是不明白如何在这种情况下实施它们,所以真的很感激推动正确的方向。提前谢谢!
答案 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() 回调。