Swift 获取 HTTP JSON 响应并使用 Codable 解析它
Posted
技术标签:
【中文标题】Swift 获取 HTTP JSON 响应并使用 Codable 解析它【英文标题】:Swift Take HTTP JSON response and parse it using Codable 【发布时间】:2018-11-27 13:18:39 【问题描述】:所以我试图通过使用 Alamofire 向后端服务器发出 http 请求来执行登录。
我有 2 个级别的请求方法,如下所示:
class func requestWith(url : URL, method: HTTPMethod, parameters: Parameters?, headers: HTTPHeaders, completion: @escaping (_ response: DataResponse<Any>) -> Void)
let sessionManager = NetworkManager.sharedInstance
sessionManager.request(url, method: method, parameters: parameters, encoding: URLEncoding.default, headers: headers)
.validate(statusCode: 200..<300)
.responseJSON (response) in
if let data = response.data
print("RESPONSE ALAMOFIRE: code = \(String(describing: response.response?.statusCode)), response = \(String(decoding: data, as: UTF8.self)) ")
completion(response)
这是 Alamofire 请求的基本方法,我将其用于我想要添加的每个功能。现在遵循为基本身份验证量身定制的实际登录方法。
class func loginAccount(usernameOrEmail: String?, password: String?, onSuccess success: @escaping (_ data : Data?) -> Void, onFailure failure: @escaping (_ error: Error?, _ errorData: Data?) -> Void)
let parameters: Parameters = [
"username" : usernameOrEmail!,
"password" : password!,
"grant_type" : "password"
]
let authUser = "WebClient"
let authPass = "Parola123"
let authData = "\(authUser):\(authPass)".data(using: String.Encoding.utf8)
guard let base64Auth = authData?.base64EncodedString(options: []) else return
let headers = [
"Authorization": "Basic \(String(describing: base64Auth))",
"Content-Type" : "application/x-www-form-urlencoded"
]
let url = Constants.urls.URL_LOGIN
APIRequest.requestWith(url: url!, method: .post, parameters: parameters, headers: headers) (result) in
switch result.result
case .success( _ ):
if let jsonValue = result.result.value
let json = JSON(jsonValue)
do
let jsonData = try json.rawData( options: [])
success(jsonData)
catch
print(error.localizedDescription)
break
case .failure(let error):
print("There was an error in logging in: \(error)")
failure(error, result.data)
break
最后,在 LoginViewController 中点击登录按钮时调用的方法:
@IBAction func signInTapped(_ sender: Any)
APIRequest.loginAccount(usernameOrEmail: emailField.text, password: passwordField.text,
onSuccess: (successData) in
self.startLoadingAnimation()
if let response = successData
print("Response123 is: \(response)")
do
let f = try JSONDecoder().decode(tokenResponse.self, from: response)
print("access token is: \(f.scope)")
catch
print(error.localizedDescription)
self.stopLoadingAnimation()
if let vc = self.storyboard?.instantiateViewController(withIdentifier: "ChatLogNavi") as? UINavigationController
self.present(vc,animated: true, completion: nil)
else
, onFailure: (error, failureData) in
var json = JSON()
do
json = try JSON(data: failureData!)
catch
let messageBody = json["message"].stringValue
let alert = UIAlertController(title: error?.localizedDescription, message: messageBody, preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "OK", style: .default))
self.present(alert, animated: true)
)
print("\n get account \n")
最重要的是,当我将响应从一种方法发送到另一种方法时,我不知道应该如何设置响应的数据类型。最后,当我到达最后一个方法时,它没有返回任何内容,并说:“无法读取数据,因为它的格式不正确。”我应该修改什么?我对这个 JSON 和 http 请求相当陌生。谢谢!
编辑:tokenResponse 声明如下:
struct tokenResponse: Codable
var tokenType: String?
var expiresIn: String?
var refreshToken: String?
var accessToken: String?
var scope: String?
enum CodingKeys: String, CodingKey
case tokenType = "token_type"
case expiresIn = "expires_in"
case refreshToken = "refresh_token"
case accessToken = "access_token"
case scope
【问题讨论】:
String(decoding: data, as: UTF8.self)
??应该是String(data: data, encoding: .utf8)
打印 print(error)
而不是 print(error.localizedDescription)
。并告诉我们出了什么问题。
@Larme typeMismatch(Swift.String, Swift.DecodingError.Context(codingPath: [CodingKeys(stringValue: "expires_in", intValue: nil)], debugDescription: "预期解码字符串但找到了一个数字而是。”,基础错误:无))
我不知道tokenResponse
结构定义/实现,但很明显,它应该以大写开头,问题是因为你有let expires_in: String
,但它应该是@987654331 @(或Double
)。好吧,请注意,如果不是这种情况,您可能希望将属性命名为 expiresIn
(驼峰式),并使用 CodingKey 来匹配蛇形大小写
请注意,在开发类似的东西时,您必须在处理 UI 的类和处理 API 的类之间划清界限。例如,这显然是 OAuth 实现。这意味着您在发送请求时,可能必须使用刷新令牌重新登录。
【参考方案1】:
我想你想从你的服务中接收一个 json!尝试用这个来改变你的第一个函数:
class func requestWith(url : URL, method: HTTPMethod, parameters: Parameters?, headers: HTTPHeaders, completion: @escaping (_ response: NSDictionary) -> Void)
let sessionManager = NetworkManager.sharedInstance
sessionManager.request(url, method: method, parameters: parameters, encoding: URLEncoding.default, headers: headers)
.validate(statusCode: 200..<300)
.responseJSON (response) in
if let result = response.result.value
let jsonResponse = result as! NSDictionary
print("Your JSON is \(jsonResponse)")
completion(jsonResponse)
因此,通过这种方式,您可以从您的函数中获得包含 JSON 的字典!之后你可以解析它来创建你的对象
【讨论】:
嗯,我不应该在完成时返回 jsonResponse 而不是响应吗?以上是关于Swift 获取 HTTP JSON 响应并使用 Codable 解析它的主要内容,如果未能解决你的问题,请参考以下文章