[英]Swift Parsing decode 2 different json with 1 url api
嗨,我是 swift 的新手,我还在学习,所以我尝试制作登录控制器并解析 json 数据,如果它更正它解析带有 id 和内容的 json 数据,并且如果登录失败,那么 json 将显示一条消息。 我已经为所有需要的值数据创建了一个结构,但我收到了这个错误,表明它为零。
所以,如果登录成功,这是 json:
[ { "id": 891, "name": "User", "email": "qdpim@immobisp.com", "status": "1" } ]
如果登录失败,这是 json:
[ { "message": "登录失败..", "status": "0" } ]
所以基本上它有一个相同的网址我猜? 但我不知道我有点卡在这里,我需要帮助
struct login : Codable {
let id : Int
let name : String
let email : String
let status : String
let message : String
init(dictionary : [String : Any]) {
id = (dictionary ["id"] as? Int)!
name = (dictionary ["name"] as? String)!
email = (dictionary ["email"] as? String)!
status = (dictionary ["status"] as? String)!
message = (dictionary ["message"] as? String)!
}
enum CodingKeys : String, CodingKey {
case id = "id"
case name = "name"
case email = "email"
case status = "status"
case message = "message"
}
}
func Login() {
let Email = EmailField.text!
let Pass = PasswordField.text!
print(api)
guard let JsonUrl = URL(string: api) else {return}
URLSession.shared.dataTask(with: JsonUrl) { (data, response, error) in
guard let data = data else {return}
do{
let parsing = try JSONDecoder().decode([login].self, from: data)
print(parsing)
self.Loginnn = parsing
let stats = self.Loginnn.map { $0.status}
if stats.contains("1"){
print("Login Success")
DispatchQueue.main.async {
self.appDelegate.loginSeque()
}
}else if stats.contains("0") {
let action = UIAlertAction(title: "Got It", style: .default, handler: nil)
let alert = UIAlertController(title: "Wrong Email / Password", message: "Please Try Again ", preferredStyle: .alert)
alert.addAction(action)
self.present(alert, animated: true, completion: nil)
// so basicly i wanna run this alert action by search status if its contains "0"
}
}
}catch{
print(error)
}
}.resume()
}
因此,当我尝试测试登录失败时,我没有在日志中的 json 中显示消息,而是显示此错误
"keyNotFound(CodingKeys(stringValue: "id", intValue: nil), Swift.DecodingError.Context(codingPath: [_JSONKey(stringValue: "Index 0", intValue: 0)], debugDescription: "没有与键 CodingKeys( stringValue: \\"id\\", intValue: nil) (\\"id\\").",underlyingError: nil))"
如果由于密码或电子邮件错误而导致登录失败,我只想弹出一些消息或警报.....所以也许有人可以帮助我如何以最佳方式做到这一点?
您可以声明成功和失败响应类型如下,
struct LoginSuccess: Decodable {
var id: Int
var name: String
var email: String
var status: String
}
struct LoginFailure: Decodable {
var status: String
var message: String
}
然后用作,
guard let JsonUrl = URL(string: api) else { return }
URLSession.shared.dataTask(with: JsonUrl) { (data, response, error) in
guard let data = data else { return }
if let success = try? JSONDecoder().decode([LoginSuccess].self, from: data).first {
GlobalVariable.UserId = String(success.id)
DispatchQueue.main.async {
self.appDelegate.loginSeque()
}
} else if let failure = try? JSONDecoder().decode([LoginFailure].self, from: data).first {
let action = UIAlertAction(title: "Got It", style: .default, handler: nil)
let alert = UIAlertController(title: "Wrong Email / Password", message: failure.message, preferredStyle: .alert)
alert.addAction(action)
self.present(alert, animated: true, completion: nil)
}
}.resume()
成功响应仅包含键(“id”、“name”、“email”、“status”)
[ { "id": 891, "name": "User", "email": "qdpim@immobisp.com", "status": "1" } ]
并且失败响应只包含键(“消息”,“状态”)
[ { "message": "登录失败..", "status": "0" } ]
如果您想对两个 JSON 响应使用相同的结构,您应该将属性设为可选
struct login : Codable {
var id: Int?
var name: String?
var email: String?
var status: String?
var message: String?
}
此外,由于您的密钥与您的属性相同,因此如果您使用JSONDecoder().decode
,则不需要enum CodingKeys
或init
在这种情况下,我会使用 JSONSerialization 将数据解码为 [[String: Any]] 并查看内容以确定它是哪种消息。
在我的代码中,我假设“状态”项告诉我们它是否成功登录,但例如可以查找“id”的存在或字典中元素的数量来确定响应的类型
do {
let result = try JSONSerialization.jsonObject(with: data) as! [[String: Any]]
if let response = result.first, let status = response["status"] as? String {
if status == "1" {
if let id = response["id"] as? Int {
let ids = String(id)
//...
}
} else {
if let message = response["message"] as? String {
print(message)
}
}
}
} catch {
print(error)
}
以下是我在您问题中的代码中使用的解决方案。 请注意,我简化了登录结构,因为它仅在登录成功时使用
struct Login {
let id : Int
let name : String
let email : String
}
do {
let result = try JSONSerialization.jsonObject(with: data) as! [[String: Any]]
if let response = result.first, let status = response["status"] as? String {
if status == "1" {
//handle success
let login = Login(id: response["id"] as? Int ?? 0,
name: response["name"] as? String ?? "",
email: response["email"] as? String ?? "")
self.Loginnn = login
DispatchQueue.main.async {
self.appDelegate.loginSeque()
}
} else {
let action = UIAlertAction(title: "Got It", style: .default, handler: nil)
let alert = UIAlertController(title: "Wrong Email / Password", message: "Please Try Again ", preferredStyle: .alert)
alert.addAction(action)
self.present(alert, animated: true, completion: nil)
}
}
} catch {
print(error)
}
您已经为此得到了一个(或三个)答案,但我想向您展示如何在不使用JSONSerialization
或推测性解码的情况下做到这一点。
所以我们有一些你想要解码的LoginSuccess
和LoginFailure
类型:
struct LoginSuccess: Decodable {
var id: Int
var name: String
var email: String
}
struct LoginFailure: Decodable {
var message: String
}
我们希望根据与这些类型的字段位于同一容器中的status
来区分它们。 所以我们创建一个enum
:
enum LoginResult: Decodable {
case success(LoginSuccess)
case failure(LoginFailure)
enum Keys: CodingKey {
case status
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: Keys.self)
if try container.decode(String.self, forKey: .status) == "1" {
self = .success(try LoginSuccess(from: decoder))
} else {
self = .failure(try LoginFailure(from: decoder))
}
}
}
注意, enum
的init
不会调用decoder.decode(LoginSuccess.self)
它传递给LoginSuccess
初始值设定项的解码器。 与LoginFailure
相同。 这意味着这些初始值设定项将从与status
字段相同的容器中提取值。
测试:
let successData = #"[ { "id": 891, "name": "User", "email": "qdpim@immobisp.com", "status": "1" } ]"#.data(using: .utf8)!
print(try JSONDecoder().decode([LoginResult].self, from: successData))
// Output:
[__lldb_expr_1.LoginResult.success(__lldb_expr_1.LoginSuccess(id: 891, name: "User", email: "qdpim@immobisp.com"))]
let failureData = #"[ { "message": "Login Failed..", "status": "0" } ]"#.data(using: .utf8)!
print(try JSONDecoder().decode([LoginResult].self, from: failureData))
// Output:
[__lldb_expr_1.LoginResult.failure(__lldb_expr_1.LoginFailure(message: "Login Failed.."))]
请注意,因为您的示例数据包含在[...]
,所以我解码了LoginResult
数组。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.