Ошибка декодирования словаря JSON для [String: Any] в Swift - PullRequest
0 голосов
/ 03 июня 2019

Я пытаюсь декодировать словарь, называемый свойствами, которые имеют 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: «Ожидаетсядекодировать строку, но вместо этого нашел число. "

Декодируемый в 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]
}

Что мне делать?

1 Ответ

1 голос
/ 03 июня 2019

Проблема в этой строке:

let properties:[String:String]

Здесь вы говорите, properties это словарь. Это не достаточно хорошо. Конечно, в JSON это словарь, но для декодирования словаря с помощью JSONDecoder вам нужна дополнительная вложенная структура, соответствующая словарю. Давайте назовем это Свойства. Так вы бы сказали

let properties:Properties

И тогда вы бы определили декодируемую структуру Properties.

Однако у вас проблема: словари properties не все имеют одинаковый набор ключей. Некоторые присутствуют, некоторые нет, каждый раз. Чтобы решить эту проблему, используйте Optionals при определении структуры Properties:

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 (тип: «FeatureCollection», функции: [Место (название места: «Международный аэропорт Лорето, Лорето, Нижняя Калифорния, 23889, Мексика»), свойства: Свойства (ориентир: Необязательный (true), адрес: ноль, категория : Необязательно ("airport"), wikidata: Необязательно ("Q1932928"), short_code: nil, maki: Необязательно ("airport")), центр: [-111.350714, 25.990894999999998]), Место (название места: "Loreto, Перу") , свойства: Свойства (ориентир: ноль, адрес: ноль, категория: ноль, викиданные: необязательно ("Q200938"), короткий код: необязательно ("PE-LOR"), маки: ноль), центр: [-74.319999999999993, -4.0 ]), Место (название места: "Лорето, Анкона, Италия", свойства: Свойства (ориентир: ноль, адрес: ноль, категория: ноль, викиданные: необязательно ("Q124110"), короткий код: ноль, маки: ноль), центр : [13.607430000000001, 43.440300000000001]), Место (название места: "Лорето, Калле 5, Ла Урбина, Сукре, Миранда, Венесуэла"), свойства: Свойства (ориентир: Необязательно (true), адрес: Необязательно ("Калле 5, La Urbina "), факультативно (" Италия " n ресторан, итальянская кухня, ресторан "), wikidata: ноль, короткий код: ноль, маки: ноль), центр: [-66.808421999999993, 10.492139999999999]), место (название места:" Loreto Coffee-Bar, Corredera baja de San Pablo, 6 , Мадрид, Мадрид 28004, Испания ", свойства: Недвижимость (ориентир: Необязательно (верно), адрес: Необязательно (" Corredera baja de San Pablo, 6 "), категория: Необязательно (" испанский ресторан, испанская еда, ресторан "), Викиданные: ноль, короткий код: ноль, маки: ноль), центр: [-3.7044929999999998, 40.421894000000002])])

Если я пропустил какие-либо возможные ключи, просто добавьте их таким же образом. Проверьте с помощью API mapbox, чтобы увидеть, есть ли другие возможности.

...