Swift 中 [String:Any] 字典的 JSON 解码错误
Error decoding JSON Dictionary of [String:Any] in Swift
我正在尝试解码一个名为 properties 的字典,它有 2 个键值对,具有不同类型的数据,String 和 Boolean。
{
"type": "FeatureCollection",
"query": [
"loreto"
],
"features": [
{
"id": "poi.738734375380",
"type": "Feature",
"place_type": [
"poi"
],
"relevance": 1,
"properties": {
"wikidata": "Q1932928",
"landmark": true,
"category": "airport",
"maki": "airport"
},
"text": "Aeropuerto Internacional de Loreto",
"place_name": "Aeropuerto Internacional de Loreto, Loreto, Baja California Sur 23889, Mexico",
"matching_text": "Loreto International Airport",
"matching_place_name": "Loreto International Airport, Loreto, Baja California Sur 23889, Mexico",
"center": [
-111.350714,
25.990895
],
"geometry": {
"coordinates": [
-111.350714,
25.990895
],
"type": "Point"
},
"context": [
{
"id": "postcode.18084443266252890",
"text": "23889"
},
{
"id": "place.14237343392099110",
"wikidata": null,
"text": "Loreto"
},
{
"id": "region.4595447518930340",
"short_code": "MX-BCS",
"wikidata": "Q46508",
"text": "Baja California Sur"
},
{
"id": "country.1891876083773450",
"short_code": "mx",
"wikidata": "Q96",
"text": "Mexico"
}
]
},
{
"id": "region.7294174250099110",
"type": "Feature",
"place_type": [
"region"
],
"relevance": 1,
"properties": {
"short_code": "PE-LOR",
"wikidata": "Q200938"
},
"text": "Loreto",
"place_name": "Loreto, Peru",
"bbox": [
-77.810369,
-8.645157,
-69.962572,
-0.029093
],
"center": [
-74.32,
-4
],
"geometry": {
"type": "Point",
"coordinates": [
-74.32,
-4
]
},
"context": [
{
"id": "country.8104362620964510",
"short_code": "pe",
"wikidata": "Q419",
"text": "Peru"
}
]
},
{
"id": "place.13763862540099110",
"type": "Feature",
"place_type": [
"place"
],
"relevance": 1,
"properties": {
"wikidata": "Q124110"
},
"text": "Loreto",
"place_name": "Loreto, Ancona, Italy",
"bbox": [
13.579312,
43.416918,
13.658326,
43.45622
],
"center": [
13.60743,
43.4403
],
"geometry": {
"type": "Point",
"coordinates": [
13.60743,
43.4403
]
},
"context": [
{
"id": "region.9523893847640810",
"short_code": "IT-AN",
"wikidata": "Q16114",
"text": "Ancona"
},
{
"id": "country.4747984886519910",
"short_code": "it",
"wikidata": "Q38",
"text": "Italy"
}
]
},
{
"id": "poi.2568390505832",
"type": "Feature",
"place_type": [
"poi"
],
"relevance": 1,
"properties": {
"landmark": true,
"address": "Calle 5, La Urbina",
"category": "italian restaurant, italian food, restaurant"
},
"text": "Loreto's",
"place_name": "Loreto's, Calle 5, La Urbina, Sucre, Miranda, Venezuela",
"center": [
-66.808422,
10.49214
],
"geometry": {
"coordinates": [
-66.808422,
10.49214
],
"type": "Point"
},
"context": [
{
"id": "place.13896838717891910",
"wikidata": "Q400079",
"text": "Sucre"
},
{
"id": "region.2525680865649430",
"short_code": "VE-M",
"wikidata": "Q191174",
"text": "Miranda"
},
{
"id": "country.5958724522570350",
"short_code": "ve",
"wikidata": "Q717",
"text": "Venezuela"
}
]
},
{
"id": "poi.2439541497917",
"type": "Feature",
"place_type": [
"poi"
],
"relevance": 1,
"properties": {
"landmark": true,
"address": "Corredera baja de San Pablo, 6",
"category": "spanish restaurant, spanish food, restaurant"
},
"text": "Loreto Coffee-Bar",
"place_name": "Loreto Coffee-Bar, Corredera baja de San Pablo, 6, Madrid, Madrid 28004, Spain",
"center": [
-3.704493,
40.421894
],
"geometry": {
"coordinates": [
-3.704493,
40.421894
],
"type": "Point"
},
"context": [
{
"id": "locality.5946271622443140",
"wikidata": "Q10387767",
"text": "Universidad"
},
{
"id": "postcode.9832348953129320",
"text": "28004"
},
{
"id": "place.10692955307562040",
"wikidata": "Q2807",
"text": "Madrid"
},
{
"id": "region.13206054317562040",
"short_code": null,
"wikidata": "Q2807",
"text": "Madrid"
},
{
"id": "country.8849824479570100",
"short_code": "es",
"wikidata": "Q29",
"text": "Spain"
}
]
}
],
"attribution": "NOTICE: © 2019 Mapbox and its suppliers. All rights reserved. Use of this data is subject to the Mapbox Terms of Service (https://www.mapbox.com/about/maps/). This response and the information it contains may not be retained. POI(s) provided by Foursquare."
}
当我使用 JSONDecoder 时出现这个错误:
"Expected to decode String but found a number instead."
Swift 中的可解码不允许使用 [String:Any]
我已经尝试过像数组一样解码,但是不,是一个字典。
struct SearchResult:Decodable{
let type:String
let features:[Place]
}
struct Place:Decodable {
let place_name:String
let properties:[String:String]
let center:[Double]
}
我该怎么办?
问题出在这一行:
let properties:[String:String]
这里你说 properties
是字典。这还不够好。当然,在 JSON 中它是一个字典,但是要使用 JSONDecoder 解码字典,您需要一个与字典匹配的进一步嵌套结构。我们称之为属性。所以你会说
let properties:Properties
然后您将定义一个可解码的 Properties 结构。
但是,您遇到了一个问题:properties
词典并不都具有相同的键集。每次都有一些存在,一些不存在。要解决这个问题,请在定义 Properties 结构时使用 Optionals:
struct SearchResult:Decodable{
let type:String
let features:[Place]
}
struct Place:Decodable {
let place_name:String
let properties:Properties
let center:[Double]
}
struct Properties:Decodable {
let landmark : Bool?
let address : String?
let category : String?
let wikidata : String?
let short_code : String?
let maki : String?
}
这似乎成功解码了您实际显示的 JSON。我明白了:
SearchResult(type: "FeatureCollection", features: [Place(place_name: "Aeropuerto Internacional de Loreto, Loreto, Baja California Sur 23889, Mexico", properties: Properties(landmark: Optional(true), address: nil, category: Optional("airport"), wikidata: Optional("Q1932928"), short_code: nil, maki: Optional("airport")), center: [-111.350714, 25.990894999999998]), Place(place_name: "Loreto, Peru", properties: Properties(landmark: nil, address: nil, category: nil, wikidata: Optional("Q200938"), short_code: Optional("PE-LOR"), maki: nil), center: [-74.319999999999993, -4.0]), Place(place_name: "Loreto, Ancona, Italy", properties: Properties(landmark: nil, address: nil, category: nil, wikidata: Optional("Q124110"), short_code: nil, maki: nil), center: [13.607430000000001, 43.440300000000001]), Place(place_name: "Loreto\'s, Calle 5, La Urbina, Sucre, Miranda, Venezuela", properties: Properties(landmark: Optional(true), address: Optional("Calle 5, La Urbina"), category: Optional("italian restaurant, italian food, restaurant"), wikidata: nil, short_code: nil, maki: nil), center: [-66.808421999999993, 10.492139999999999]), Place(place_name: "Loreto Coffee-Bar, Corredera baja de San Pablo, 6, Madrid, Madrid 28004, Spain", properties: Properties(landmark: Optional(true), address: Optional("Corredera baja de San Pablo, 6"), category: Optional("spanish restaurant, spanish food, restaurant"), wikidata: nil, short_code: nil, maki: nil), center: [-3.7044929999999998, 40.421894000000002])])
如果我遗漏了任何可能的键,请以相同的方式添加它们。检查 mapbox api 看看是否还有其他可能性。
我正在尝试解码一个名为 properties 的字典,它有 2 个键值对,具有不同类型的数据,String 和 Boolean。
{
"type": "FeatureCollection",
"query": [
"loreto"
],
"features": [
{
"id": "poi.738734375380",
"type": "Feature",
"place_type": [
"poi"
],
"relevance": 1,
"properties": {
"wikidata": "Q1932928",
"landmark": true,
"category": "airport",
"maki": "airport"
},
"text": "Aeropuerto Internacional de Loreto",
"place_name": "Aeropuerto Internacional de Loreto, Loreto, Baja California Sur 23889, Mexico",
"matching_text": "Loreto International Airport",
"matching_place_name": "Loreto International Airport, Loreto, Baja California Sur 23889, Mexico",
"center": [
-111.350714,
25.990895
],
"geometry": {
"coordinates": [
-111.350714,
25.990895
],
"type": "Point"
},
"context": [
{
"id": "postcode.18084443266252890",
"text": "23889"
},
{
"id": "place.14237343392099110",
"wikidata": null,
"text": "Loreto"
},
{
"id": "region.4595447518930340",
"short_code": "MX-BCS",
"wikidata": "Q46508",
"text": "Baja California Sur"
},
{
"id": "country.1891876083773450",
"short_code": "mx",
"wikidata": "Q96",
"text": "Mexico"
}
]
},
{
"id": "region.7294174250099110",
"type": "Feature",
"place_type": [
"region"
],
"relevance": 1,
"properties": {
"short_code": "PE-LOR",
"wikidata": "Q200938"
},
"text": "Loreto",
"place_name": "Loreto, Peru",
"bbox": [
-77.810369,
-8.645157,
-69.962572,
-0.029093
],
"center": [
-74.32,
-4
],
"geometry": {
"type": "Point",
"coordinates": [
-74.32,
-4
]
},
"context": [
{
"id": "country.8104362620964510",
"short_code": "pe",
"wikidata": "Q419",
"text": "Peru"
}
]
},
{
"id": "place.13763862540099110",
"type": "Feature",
"place_type": [
"place"
],
"relevance": 1,
"properties": {
"wikidata": "Q124110"
},
"text": "Loreto",
"place_name": "Loreto, Ancona, Italy",
"bbox": [
13.579312,
43.416918,
13.658326,
43.45622
],
"center": [
13.60743,
43.4403
],
"geometry": {
"type": "Point",
"coordinates": [
13.60743,
43.4403
]
},
"context": [
{
"id": "region.9523893847640810",
"short_code": "IT-AN",
"wikidata": "Q16114",
"text": "Ancona"
},
{
"id": "country.4747984886519910",
"short_code": "it",
"wikidata": "Q38",
"text": "Italy"
}
]
},
{
"id": "poi.2568390505832",
"type": "Feature",
"place_type": [
"poi"
],
"relevance": 1,
"properties": {
"landmark": true,
"address": "Calle 5, La Urbina",
"category": "italian restaurant, italian food, restaurant"
},
"text": "Loreto's",
"place_name": "Loreto's, Calle 5, La Urbina, Sucre, Miranda, Venezuela",
"center": [
-66.808422,
10.49214
],
"geometry": {
"coordinates": [
-66.808422,
10.49214
],
"type": "Point"
},
"context": [
{
"id": "place.13896838717891910",
"wikidata": "Q400079",
"text": "Sucre"
},
{
"id": "region.2525680865649430",
"short_code": "VE-M",
"wikidata": "Q191174",
"text": "Miranda"
},
{
"id": "country.5958724522570350",
"short_code": "ve",
"wikidata": "Q717",
"text": "Venezuela"
}
]
},
{
"id": "poi.2439541497917",
"type": "Feature",
"place_type": [
"poi"
],
"relevance": 1,
"properties": {
"landmark": true,
"address": "Corredera baja de San Pablo, 6",
"category": "spanish restaurant, spanish food, restaurant"
},
"text": "Loreto Coffee-Bar",
"place_name": "Loreto Coffee-Bar, Corredera baja de San Pablo, 6, Madrid, Madrid 28004, Spain",
"center": [
-3.704493,
40.421894
],
"geometry": {
"coordinates": [
-3.704493,
40.421894
],
"type": "Point"
},
"context": [
{
"id": "locality.5946271622443140",
"wikidata": "Q10387767",
"text": "Universidad"
},
{
"id": "postcode.9832348953129320",
"text": "28004"
},
{
"id": "place.10692955307562040",
"wikidata": "Q2807",
"text": "Madrid"
},
{
"id": "region.13206054317562040",
"short_code": null,
"wikidata": "Q2807",
"text": "Madrid"
},
{
"id": "country.8849824479570100",
"short_code": "es",
"wikidata": "Q29",
"text": "Spain"
}
]
}
],
"attribution": "NOTICE: © 2019 Mapbox and its suppliers. All rights reserved. Use of this data is subject to the Mapbox Terms of Service (https://www.mapbox.com/about/maps/). This response and the information it contains may not be retained. POI(s) provided by Foursquare."
}
当我使用 JSONDecoder 时出现这个错误: "Expected to decode String but found a number instead."
Swift 中的可解码不允许使用 [String:Any] 我已经尝试过像数组一样解码,但是不,是一个字典。
struct SearchResult:Decodable{
let type:String
let features:[Place]
}
struct Place:Decodable {
let place_name:String
let properties:[String:String]
let center:[Double]
}
我该怎么办?
问题出在这一行:
let properties:[String:String]
这里你说 properties
是字典。这还不够好。当然,在 JSON 中它是一个字典,但是要使用 JSONDecoder 解码字典,您需要一个与字典匹配的进一步嵌套结构。我们称之为属性。所以你会说
let properties:Properties
然后您将定义一个可解码的 Properties 结构。
但是,您遇到了一个问题:properties
词典并不都具有相同的键集。每次都有一些存在,一些不存在。要解决这个问题,请在定义 Properties 结构时使用 Optionals:
struct SearchResult:Decodable{
let type:String
let features:[Place]
}
struct Place:Decodable {
let place_name:String
let properties:Properties
let center:[Double]
}
struct Properties:Decodable {
let landmark : Bool?
let address : String?
let category : String?
let wikidata : String?
let short_code : String?
let maki : String?
}
这似乎成功解码了您实际显示的 JSON。我明白了:
SearchResult(type: "FeatureCollection", features: [Place(place_name: "Aeropuerto Internacional de Loreto, Loreto, Baja California Sur 23889, Mexico", properties: Properties(landmark: Optional(true), address: nil, category: Optional("airport"), wikidata: Optional("Q1932928"), short_code: nil, maki: Optional("airport")), center: [-111.350714, 25.990894999999998]), Place(place_name: "Loreto, Peru", properties: Properties(landmark: nil, address: nil, category: nil, wikidata: Optional("Q200938"), short_code: Optional("PE-LOR"), maki: nil), center: [-74.319999999999993, -4.0]), Place(place_name: "Loreto, Ancona, Italy", properties: Properties(landmark: nil, address: nil, category: nil, wikidata: Optional("Q124110"), short_code: nil, maki: nil), center: [13.607430000000001, 43.440300000000001]), Place(place_name: "Loreto\'s, Calle 5, La Urbina, Sucre, Miranda, Venezuela", properties: Properties(landmark: Optional(true), address: Optional("Calle 5, La Urbina"), category: Optional("italian restaurant, italian food, restaurant"), wikidata: nil, short_code: nil, maki: nil), center: [-66.808421999999993, 10.492139999999999]), Place(place_name: "Loreto Coffee-Bar, Corredera baja de San Pablo, 6, Madrid, Madrid 28004, Spain", properties: Properties(landmark: Optional(true), address: Optional("Corredera baja de San Pablo, 6"), category: Optional("spanish restaurant, spanish food, restaurant"), wikidata: nil, short_code: nil, maki: nil), center: [-3.7044929999999998, 40.421894000000002])])
如果我遗漏了任何可能的键,请以相同的方式添加它们。检查 mapbox api 看看是否还有其他可能性。