Swift 解析解码 2 个不同的 json 与 1 url api
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": "Login Failed..",
"status": "0"
} ]
所以基本上它有相同的 url 我猜?但我不知道我有点卡在这里,我需要帮助
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 { [=14=].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: "No value associated with key
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")
[ { "message": "Login Failed..", "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]] 并查看内容以确定它是哪种消息。
在我的代码中,我假设 "status" 项告诉我们登录是否成功,但是例如可以查找 "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
的数组。
嗨,我是 swift 的新手,我还在学习,所以我尝试制作登录控制器并解析一个 json 数据,如果它更正它解析一个带有 id 的 json 数据和东西,如果登录失败,json 将显示一条消息。我已经为所有需要的值数据创建了一个结构,但是我得到了这个错误,说它是零。
所以,这是 json 如果登录成功:
[ { "id": 891, "name": "User", "email": "qdpim@immobisp.com", "status": "1" } ]
这是 json 如果登录失败:
[ { "message": "Login Failed..", "status": "0" } ]
所以基本上它有相同的 url 我猜?但我不知道我有点卡在这里,我需要帮助
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 { [=14=].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: "No value associated with key 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")
[ { "message": "Login Failed..", "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]] 并查看内容以确定它是哪种消息。
在我的代码中,我假设 "status" 项告诉我们登录是否成功,但是例如可以查找 "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
的数组。