Swift/AlamoFire:无法解码 JSON 响应
Swift/AlamoFire: Unable to decode JSON response
我正在尝试使用 AlamoFire and decode them using the built-in .responseDecodable
handler 发出请求。我到达的 API 端点是 https://api.linode.com/v4/regions
.
Request.swift
:
import Foundation
import Alamofire
func getRegions() {
AF.request("https://api.linode.com/v4/regions")
.validate()
.responseDecodable(of: Region.self) { (response) in
guard let regions = response.value else { return }
print(regions)
debugPrint("Response: \(response)")
}
}
当我构建和 运行 二进制文件并调用 getRegions()
时,我在控制台中没有输出(调试或其他)。当我像这样更改 getRegions()
并删除 .responseDecodable
时,我在控制台中得到了原始的 JSON:
let regionRequest = AF.request("https://api.linode.com/v4/regions")
regionRequest.responseJSON { (data) in
print(data)
这是我的区域模型:
Region.swift
:
import Foundation
struct Region: Decodable {
enum resolvers: String, Decodable {
case ipv4, ipv6
}
let capabilities: Array<String>
let country: String
let id: String
let resolvers: Set<resolvers>
let status: String
let page: Int
let pages: Int
let results: Int
enum CodingKeys: String, CodingKey {
case capabilities
case country
case resolvers
case status
case id
case page
case pages
case results
}
}
这是 API 的 JSON 响应:
data = (
{
capabilities = (
Linodes,
NodeBalancers,
"Block Storage",
"GPU Linodes",
Kubernetes,
"Cloud Firewall",
Vlans
);
country = in;
id = "ap-west";
resolvers = {
ipv4 = "172.105.34.5,172.105.35.5,172.105.36.5,172.105.37.5,172.105.38.5,172.105.39.5,172.105.40.5,172.105.41.5,172.105.42.5,172.105.43.5";
ipv6 = "2400:8904::f03c:91ff:fea5:659,2400:8904::f03c:91ff:fea5:9282,2400:8904::f03c:91ff:fea5:b9b3,2400:8904::f03c:91ff:fea5:925a,2400:8904::f03c:91ff:fea5:22cb,2400:8904::f03c:91ff:fea5:227a,2400:8904::f03c:91ff:fea5:924c,2400:8904::f03c:91ff:fea5:f7e2,2400:8904::f03c:91ff:fea5:2205,2400:8904::f03c:91ff:fea5:9207";
};
status = ok;
},
{
capabilities = (
Linodes,
NodeBalancers,
"Block Storage",
Kubernetes,
"Cloud Firewall",
Vlans
);
country = ca;
id = "ca-central";
resolvers = {
ipv4 = "172.105.0.5,172.105.3.5,172.105.4.5,172.105.5.5,172.105.6.5,172.105.7.5,172.105.8.5,172.105.9.5,172.105.10.5,172.105.11.5";
ipv6 = "2600:3c04::f03c:91ff:fea9:f63,2600:3c04::f03c:91ff:fea9:f6d,2600:3c04::f03c:91ff:fea9:f80,2600:3c04::f03c:91ff:fea9:f0f,2600:3c04::f03c:91ff:fea9:f99,2600:3c04::f03c:91ff:fea9:fbd,2600:3c04::f03c:91ff:fea9:fdd,2600:3c04::f03c:91ff:fea9:fe2,2600:3c04::f03c:91ff:fea9:f68,2600:3c04::f03c:91ff:fea9:f4a";
};
status = ok;
},
{
capabilities = (
Linodes,
NodeBalancers,
"Block Storage",
Kubernetes,
"Cloud Firewall",
Vlans
);
country = au;
id = "ap-southeast";
resolvers = {
ipv4 = "172.105.166.5,172.105.169.5,172.105.168.5,172.105.172.5,172.105.162.5,172.105.170.5,172.105.167.5,172.105.171.5,172.105.181.5,172.105.161.5";
ipv6 = "2400:8907::f03c:92ff:fe6e:ec8,2400:8907::f03c:92ff:fe6e:98e4,2400:8907::f03c:92ff:fe6e:1c58,2400:8907::f03c:92ff:fe6e:c299,2400:8907::f03c:92ff:fe6e:c210,2400:8907::f03c:92ff:fe6e:c219,2400:8907::f03c:92ff:fe6e:1c5c,2400:8907::f03c:92ff:fe6e:c24e,2400:8907::f03c:92ff:fe6e:e6b,2400:8907::f03c:92ff:fe6e:e3d";
};
status = ok;
},
{
capabilities = (
Linodes,
NodeBalancers,
"Block Storage",
Kubernetes,
"Cloud Firewall"
);
country = us;
id = "us-central";
resolvers = {
ipv4 = "72.14.179.5,72.14.188.5,173.255.199.5,66.228.53.5,96.126.122.5,96.126.124.5,96.126.127.5,198.58.107.5,198.58.111.5,23.239.24.5";
ipv6 = "2600:3c00::2,2600:3c00::9,2600:3c00::7,2600:3c00::5,2600:3c00::3,2600:3c00::8,2600:3c00::6,2600:3c00::4,2600:3c00::c,2600:3c00::b";
};
status = ok;
},
{
capabilities = (
Linodes,
NodeBalancers,
"Block Storage",
Kubernetes,
"Cloud Firewall"
);
country = us;
id = "us-west";
resolvers = {
ipv4 = "173.230.145.5,173.230.147.5,173.230.155.5,173.255.212.5,173.255.219.5,173.255.241.5,173.255.243.5,173.255.244.5,74.207.241.5,74.207.242.5";
ipv6 = "2600:3c01::2,2600:3c01::9,2600:3c01::5,2600:3c01::7,2600:3c01::3,2600:3c01::8,2600:3c01::4,2600:3c01::b,2600:3c01::c,2600:3c01::6";
};
status = ok;
},
{
capabilities = (
Linodes,
NodeBalancers,
"Cloud Firewall",
Vlans
);
country = us;
id = "us-southeast";
resolvers = {
ipv4 = "74.207.231.5,173.230.128.5,173.230.129.5,173.230.136.5,173.230.140.5,66.228.59.5,66.228.62.5,50.116.35.5,50.116.41.5,23.239.18.5";
ipv6 = "2600:3c02::3,2600:3c02::5,2600:3c02::4,2600:3c02::6,2600:3c02::c,2600:3c02::7,2600:3c02::2,2600:3c02::9,2600:3c02::8,2600:3c02::b";
};
status = ok;
},
{
capabilities = (
Linodes,
NodeBalancers,
"Block Storage",
"Object Storage",
"GPU Linodes",
Kubernetes
);
country = us;
id = "us-east";
resolvers = {
ipv4 = "66.228.42.5,96.126.106.5,50.116.53.5,50.116.58.5,50.116.61.5,50.116.62.5,66.175.211.5,97.107.133.4,207.192.69.4,207.192.69.5";
ipv6 = "2600:3c03::7,2600:3c03::4,2600:3c03::9,2600:3c03::6,2600:3c03::3,2600:3c03::c,2600:3c03::5,2600:3c03::b,2600:3c03::2,2600:3c03::8";
};
status = ok;
},
{
capabilities = (
Linodes,
NodeBalancers,
"Block Storage",
Kubernetes,
"Cloud Firewall"
);
country = uk;
id = "eu-west";
resolvers = {
ipv4 = "178.79.182.5,176.58.107.5,176.58.116.5,176.58.121.5,151.236.220.5,212.71.252.5,212.71.253.5,109.74.192.20,109.74.193.20,109.74.194.20";
ipv6 = "2a01:7e00::9,2a01:7e00::3,2a01:7e00::c,2a01:7e00::5,2a01:7e00::6,2a01:7e00::8,2a01:7e00::b,2a01:7e00::4,2a01:7e00::7,2a01:7e00::2";
};
status = ok;
},
{
capabilities = (
Linodes,
NodeBalancers,
"Block Storage",
"Object Storage",
"GPU Linodes",
Kubernetes
);
country = sg;
id = "ap-south";
resolvers = {
ipv4 = "139.162.11.5,139.162.13.5,139.162.14.5,139.162.15.5,139.162.16.5,139.162.21.5,139.162.27.5,103.3.60.18,103.3.60.19,103.3.60.20";
ipv6 = "2400:8901::5,2400:8901::4,2400:8901::b,2400:8901::3,2400:8901::9,2400:8901::2,2400:8901::8,2400:8901::7,2400:8901::c,2400:8901::6";
};
status = ok;
},
{
capabilities = (
Linodes,
NodeBalancers,
"Block Storage",
"Object Storage",
"GPU Linodes",
Kubernetes
);
country = de;
id = "eu-central";
resolvers = {
ipv4 = "139.162.130.5,139.162.131.5,139.162.132.5,139.162.133.5,139.162.134.5,139.162.135.5,139.162.136.5,139.162.137.5,139.162.138.5,139.162.139.5";
ipv6 = "2a01:7e01::5,2a01:7e01::9,2a01:7e01::7,2a01:7e01::c,2a01:7e01::2,2a01:7e01::4,2a01:7e01::3,2a01:7e01::6,2a01:7e01::b,2a01:7e01::8";
};
status = ok;
},
{
capabilities = (
Linodes,
NodeBalancers,
"Block Storage",
Kubernetes
);
country = jp;
id = "ap-northeast";
resolvers = {
ipv4 = "139.162.66.5,139.162.67.5,139.162.68.5,139.162.69.5,139.162.70.5,139.162.71.5,139.162.72.5,139.162.73.5,139.162.74.5,139.162.75.5";
ipv6 = "2400:8902::3,2400:8902::6,2400:8902::c,2400:8902::4,2400:8902::2,2400:8902::8,2400:8902::7,2400:8902::5,2400:8902::b,2400:8902::9";
};
status = ok;
}
);
page = 1;
pages = 1;
results = 11;
})
我在这里做错了什么?我怀疑它与 Region 结构有关,但我一直无法弄清楚。任何帮助将不胜感激,谢谢!
更新:
我稍微简化了我的 Region 模型并添加了选项:
struct Data: Codable {
let data: [Region]
let page, pages, results: Int
}
struct Region: Codable {
let capabilities: [String]?
let country, id: String?
let status: String?
let resolvers: Resolvers?
enum CodingKeys: String, CodingKey {
case country
case id
case status
case capabilities
case resolvers
}
}
struct Resolvers: Codable {
let ipv4, ipv6: String
}
我现在使用 AlamoFire 得到了成功的响应(虽然一切都是 nil
– 进步了!):
success(.Region(capabilities: nil, country: nil, id: nil, status: nil, resolvers: nil))
您可以使用(https://apps.apple.com/us/app/paste-json-as-code-quicktype/id1330801220?mt=12) App Store 中的这个应用程序来解析和解码json,然后您可以使用alamofire 请求并以jsonString 作为响应并解码您的 json 回复。 quickType 为您的数据结构提供自定义 json 解码器,您可以像这样解码您的 reponseString(您的 responseString 中的数据):
do {
let json = try Data.init(data)
}
catch let err {
print(err.localizedDescription)
}
感谢所有评论的人!我能够通过添加丢失的编码密钥来解决这个问题。我创建了 Regions.swift
,它看起来像这样:
import Foundation
struct Regions: Decodable {
let all: [Region]
enum CodingKeys: String, CodingKey {
case all = "data"
}
}
API 响应封装在 data
中。一旦我添加了这个编码密钥,我就能够得到我正在寻找的解码响应:
AF.request("https://api.linode.com/v4/regions")
.validate()
.responseDecodable(of: Regions.self) {(response) in
guard let regions = response.value else {return}
print(regions.all[0].self)
}
回复:
Region(capabilities: ["Linodes", "NodeBalancers", "Block Storage", "GPU Linodes", "Kubernetes", "Cloud Firewall", "Vlans"], country: "in", id: "ap-west", status: "ok", resolvers: QuickCloud.Resolvers(ipv4: "172.105.34.5,172.105.35.5,172.105.36.5,172.105.37.5,172.105.38.5,172.105.39.5,172.105.40.5,172.105.41.5,172.105.42.5,172.105.43.5", ipv6: "2400:8904::f03c:91ff:fea5:659,2400:8904::f03c:91ff:fea5:9282,2400:8904::f03c:91ff:fea5:b9b3,2400:8904::f03c:91ff:fea5:925a,2400:8904::f03c:91ff:fea5:22cb,2400:8904::f03c:91ff:fea5:227a,2400:8904::f03c:91ff:fea5:924c,2400:8904::f03c:91ff:fea5:f7e2,2400:8904::f03c:91ff:fea5:2205,2400:8904::f03c:91ff:fea5:9207"))
我正在尝试使用 AlamoFire and decode them using the built-in .responseDecodable
handler 发出请求。我到达的 API 端点是 https://api.linode.com/v4/regions
.
Request.swift
:
import Foundation
import Alamofire
func getRegions() {
AF.request("https://api.linode.com/v4/regions")
.validate()
.responseDecodable(of: Region.self) { (response) in
guard let regions = response.value else { return }
print(regions)
debugPrint("Response: \(response)")
}
}
当我构建和 运行 二进制文件并调用 getRegions()
时,我在控制台中没有输出(调试或其他)。当我像这样更改 getRegions()
并删除 .responseDecodable
时,我在控制台中得到了原始的 JSON:
let regionRequest = AF.request("https://api.linode.com/v4/regions")
regionRequest.responseJSON { (data) in
print(data)
这是我的区域模型:
Region.swift
:
import Foundation
struct Region: Decodable {
enum resolvers: String, Decodable {
case ipv4, ipv6
}
let capabilities: Array<String>
let country: String
let id: String
let resolvers: Set<resolvers>
let status: String
let page: Int
let pages: Int
let results: Int
enum CodingKeys: String, CodingKey {
case capabilities
case country
case resolvers
case status
case id
case page
case pages
case results
}
}
这是 API 的 JSON 响应:
data = (
{
capabilities = (
Linodes,
NodeBalancers,
"Block Storage",
"GPU Linodes",
Kubernetes,
"Cloud Firewall",
Vlans
);
country = in;
id = "ap-west";
resolvers = {
ipv4 = "172.105.34.5,172.105.35.5,172.105.36.5,172.105.37.5,172.105.38.5,172.105.39.5,172.105.40.5,172.105.41.5,172.105.42.5,172.105.43.5";
ipv6 = "2400:8904::f03c:91ff:fea5:659,2400:8904::f03c:91ff:fea5:9282,2400:8904::f03c:91ff:fea5:b9b3,2400:8904::f03c:91ff:fea5:925a,2400:8904::f03c:91ff:fea5:22cb,2400:8904::f03c:91ff:fea5:227a,2400:8904::f03c:91ff:fea5:924c,2400:8904::f03c:91ff:fea5:f7e2,2400:8904::f03c:91ff:fea5:2205,2400:8904::f03c:91ff:fea5:9207";
};
status = ok;
},
{
capabilities = (
Linodes,
NodeBalancers,
"Block Storage",
Kubernetes,
"Cloud Firewall",
Vlans
);
country = ca;
id = "ca-central";
resolvers = {
ipv4 = "172.105.0.5,172.105.3.5,172.105.4.5,172.105.5.5,172.105.6.5,172.105.7.5,172.105.8.5,172.105.9.5,172.105.10.5,172.105.11.5";
ipv6 = "2600:3c04::f03c:91ff:fea9:f63,2600:3c04::f03c:91ff:fea9:f6d,2600:3c04::f03c:91ff:fea9:f80,2600:3c04::f03c:91ff:fea9:f0f,2600:3c04::f03c:91ff:fea9:f99,2600:3c04::f03c:91ff:fea9:fbd,2600:3c04::f03c:91ff:fea9:fdd,2600:3c04::f03c:91ff:fea9:fe2,2600:3c04::f03c:91ff:fea9:f68,2600:3c04::f03c:91ff:fea9:f4a";
};
status = ok;
},
{
capabilities = (
Linodes,
NodeBalancers,
"Block Storage",
Kubernetes,
"Cloud Firewall",
Vlans
);
country = au;
id = "ap-southeast";
resolvers = {
ipv4 = "172.105.166.5,172.105.169.5,172.105.168.5,172.105.172.5,172.105.162.5,172.105.170.5,172.105.167.5,172.105.171.5,172.105.181.5,172.105.161.5";
ipv6 = "2400:8907::f03c:92ff:fe6e:ec8,2400:8907::f03c:92ff:fe6e:98e4,2400:8907::f03c:92ff:fe6e:1c58,2400:8907::f03c:92ff:fe6e:c299,2400:8907::f03c:92ff:fe6e:c210,2400:8907::f03c:92ff:fe6e:c219,2400:8907::f03c:92ff:fe6e:1c5c,2400:8907::f03c:92ff:fe6e:c24e,2400:8907::f03c:92ff:fe6e:e6b,2400:8907::f03c:92ff:fe6e:e3d";
};
status = ok;
},
{
capabilities = (
Linodes,
NodeBalancers,
"Block Storage",
Kubernetes,
"Cloud Firewall"
);
country = us;
id = "us-central";
resolvers = {
ipv4 = "72.14.179.5,72.14.188.5,173.255.199.5,66.228.53.5,96.126.122.5,96.126.124.5,96.126.127.5,198.58.107.5,198.58.111.5,23.239.24.5";
ipv6 = "2600:3c00::2,2600:3c00::9,2600:3c00::7,2600:3c00::5,2600:3c00::3,2600:3c00::8,2600:3c00::6,2600:3c00::4,2600:3c00::c,2600:3c00::b";
};
status = ok;
},
{
capabilities = (
Linodes,
NodeBalancers,
"Block Storage",
Kubernetes,
"Cloud Firewall"
);
country = us;
id = "us-west";
resolvers = {
ipv4 = "173.230.145.5,173.230.147.5,173.230.155.5,173.255.212.5,173.255.219.5,173.255.241.5,173.255.243.5,173.255.244.5,74.207.241.5,74.207.242.5";
ipv6 = "2600:3c01::2,2600:3c01::9,2600:3c01::5,2600:3c01::7,2600:3c01::3,2600:3c01::8,2600:3c01::4,2600:3c01::b,2600:3c01::c,2600:3c01::6";
};
status = ok;
},
{
capabilities = (
Linodes,
NodeBalancers,
"Cloud Firewall",
Vlans
);
country = us;
id = "us-southeast";
resolvers = {
ipv4 = "74.207.231.5,173.230.128.5,173.230.129.5,173.230.136.5,173.230.140.5,66.228.59.5,66.228.62.5,50.116.35.5,50.116.41.5,23.239.18.5";
ipv6 = "2600:3c02::3,2600:3c02::5,2600:3c02::4,2600:3c02::6,2600:3c02::c,2600:3c02::7,2600:3c02::2,2600:3c02::9,2600:3c02::8,2600:3c02::b";
};
status = ok;
},
{
capabilities = (
Linodes,
NodeBalancers,
"Block Storage",
"Object Storage",
"GPU Linodes",
Kubernetes
);
country = us;
id = "us-east";
resolvers = {
ipv4 = "66.228.42.5,96.126.106.5,50.116.53.5,50.116.58.5,50.116.61.5,50.116.62.5,66.175.211.5,97.107.133.4,207.192.69.4,207.192.69.5";
ipv6 = "2600:3c03::7,2600:3c03::4,2600:3c03::9,2600:3c03::6,2600:3c03::3,2600:3c03::c,2600:3c03::5,2600:3c03::b,2600:3c03::2,2600:3c03::8";
};
status = ok;
},
{
capabilities = (
Linodes,
NodeBalancers,
"Block Storage",
Kubernetes,
"Cloud Firewall"
);
country = uk;
id = "eu-west";
resolvers = {
ipv4 = "178.79.182.5,176.58.107.5,176.58.116.5,176.58.121.5,151.236.220.5,212.71.252.5,212.71.253.5,109.74.192.20,109.74.193.20,109.74.194.20";
ipv6 = "2a01:7e00::9,2a01:7e00::3,2a01:7e00::c,2a01:7e00::5,2a01:7e00::6,2a01:7e00::8,2a01:7e00::b,2a01:7e00::4,2a01:7e00::7,2a01:7e00::2";
};
status = ok;
},
{
capabilities = (
Linodes,
NodeBalancers,
"Block Storage",
"Object Storage",
"GPU Linodes",
Kubernetes
);
country = sg;
id = "ap-south";
resolvers = {
ipv4 = "139.162.11.5,139.162.13.5,139.162.14.5,139.162.15.5,139.162.16.5,139.162.21.5,139.162.27.5,103.3.60.18,103.3.60.19,103.3.60.20";
ipv6 = "2400:8901::5,2400:8901::4,2400:8901::b,2400:8901::3,2400:8901::9,2400:8901::2,2400:8901::8,2400:8901::7,2400:8901::c,2400:8901::6";
};
status = ok;
},
{
capabilities = (
Linodes,
NodeBalancers,
"Block Storage",
"Object Storage",
"GPU Linodes",
Kubernetes
);
country = de;
id = "eu-central";
resolvers = {
ipv4 = "139.162.130.5,139.162.131.5,139.162.132.5,139.162.133.5,139.162.134.5,139.162.135.5,139.162.136.5,139.162.137.5,139.162.138.5,139.162.139.5";
ipv6 = "2a01:7e01::5,2a01:7e01::9,2a01:7e01::7,2a01:7e01::c,2a01:7e01::2,2a01:7e01::4,2a01:7e01::3,2a01:7e01::6,2a01:7e01::b,2a01:7e01::8";
};
status = ok;
},
{
capabilities = (
Linodes,
NodeBalancers,
"Block Storage",
Kubernetes
);
country = jp;
id = "ap-northeast";
resolvers = {
ipv4 = "139.162.66.5,139.162.67.5,139.162.68.5,139.162.69.5,139.162.70.5,139.162.71.5,139.162.72.5,139.162.73.5,139.162.74.5,139.162.75.5";
ipv6 = "2400:8902::3,2400:8902::6,2400:8902::c,2400:8902::4,2400:8902::2,2400:8902::8,2400:8902::7,2400:8902::5,2400:8902::b,2400:8902::9";
};
status = ok;
}
);
page = 1;
pages = 1;
results = 11;
})
我在这里做错了什么?我怀疑它与 Region 结构有关,但我一直无法弄清楚。任何帮助将不胜感激,谢谢!
更新:
我稍微简化了我的 Region 模型并添加了选项:
struct Data: Codable {
let data: [Region]
let page, pages, results: Int
}
struct Region: Codable {
let capabilities: [String]?
let country, id: String?
let status: String?
let resolvers: Resolvers?
enum CodingKeys: String, CodingKey {
case country
case id
case status
case capabilities
case resolvers
}
}
struct Resolvers: Codable {
let ipv4, ipv6: String
}
我现在使用 AlamoFire 得到了成功的响应(虽然一切都是 nil
– 进步了!):
success(.Region(capabilities: nil, country: nil, id: nil, status: nil, resolvers: nil))
您可以使用(https://apps.apple.com/us/app/paste-json-as-code-quicktype/id1330801220?mt=12) App Store 中的这个应用程序来解析和解码json,然后您可以使用alamofire 请求并以jsonString 作为响应并解码您的 json 回复。 quickType 为您的数据结构提供自定义 json 解码器,您可以像这样解码您的 reponseString(您的 responseString 中的数据):
do {
let json = try Data.init(data)
}
catch let err {
print(err.localizedDescription)
}
感谢所有评论的人!我能够通过添加丢失的编码密钥来解决这个问题。我创建了 Regions.swift
,它看起来像这样:
import Foundation
struct Regions: Decodable {
let all: [Region]
enum CodingKeys: String, CodingKey {
case all = "data"
}
}
API 响应封装在 data
中。一旦我添加了这个编码密钥,我就能够得到我正在寻找的解码响应:
AF.request("https://api.linode.com/v4/regions")
.validate()
.responseDecodable(of: Regions.self) {(response) in
guard let regions = response.value else {return}
print(regions.all[0].self)
}
回复:
Region(capabilities: ["Linodes", "NodeBalancers", "Block Storage", "GPU Linodes", "Kubernetes", "Cloud Firewall", "Vlans"], country: "in", id: "ap-west", status: "ok", resolvers: QuickCloud.Resolvers(ipv4: "172.105.34.5,172.105.35.5,172.105.36.5,172.105.37.5,172.105.38.5,172.105.39.5,172.105.40.5,172.105.41.5,172.105.42.5,172.105.43.5", ipv6: "2400:8904::f03c:91ff:fea5:659,2400:8904::f03c:91ff:fea5:9282,2400:8904::f03c:91ff:fea5:b9b3,2400:8904::f03c:91ff:fea5:925a,2400:8904::f03c:91ff:fea5:22cb,2400:8904::f03c:91ff:fea5:227a,2400:8904::f03c:91ff:fea5:924c,2400:8904::f03c:91ff:fea5:f7e2,2400:8904::f03c:91ff:fea5:2205,2400:8904::f03c:91ff:fea5:9207"))