Устранение вспомогательных методов быстрого ввода при разборе JSON в Swift

Я заметил, что хотя Quicktype.io очень хорошо справляется с парсингом JSON в SWIFt, иногда он прибегает к множеству вспомогательных функций и методов. Для последующего было сгенерировано около 15 дополнительных методов. Некоторые из них знакомы, такие как NSNull, однако два незнакомы мне, например JSONAny, и кажется, что должен быть способ их обойти. Например, в классе JSONAny около 12 функций, и он используется для анализа только одного поля, которое не так важно для меня.

Вот как выглядит JSON:

[{"name":"Afghanistan","topLevelDomain":[".af"],"alpha2Code":"AF","alpha3Code":"AFG","callingCodes":["93"],"capital":"Kabul","altSpellings":["AF","Afġānistān"],"region":"Asia","subregion":"Southern Asia","population":27657145,"latlng":[33.0,65.0],"demonym":"Afghan","area":652230.0,"gini":27.8,"timezones":["UTC+04:30"],"borders":["IRN","PAK","TKM","UZB","TJK","CHN"],"nativeName":"افغانستان","numericCode":"004","currencies":[{"code":"AFN","name":"Afghan afghani","symbol":"؋"}],"languages":[{"iso639_1":"ps","iso639_2":"pus","name":"Pashto","nativeName":"پښتو"},{"iso639_1":"uz","iso639_2":"uzb","name":"Uzbek","nativeName":"Oʻzbek"},{"iso639_1":"tk","iso639_2":"tuk","name":"Turkmen","nativeName":"Türkmen"}],"translations":{"de":"Afghanistan","es":"Afganistán","fr":"Afghanistan","ja":"アフガニスタン","it":"Afghanistan","br":"Afeganistão","pt":"Afeganistão","nl":"Afghanistan","hr":"Afganistan","fa":"افغانستان"},"flag":"https://restcountries.eu/data/afg.svg","regionalBlocs":[{"acronym":"SAARC","name":"South Asian Association for Regional Cooperation","otherAcronyms":[],"otherNames":[]}],"cioc":"AFG"}]

Я не буду приводить весь код, что эта структура находится на один уровень ниже основной структуры:

 struct CountryReturnedElement: Codable {
       //...various fields  
        let regionalBlocs: [RegionalBloc]
    }

   // MARK: - RegionalBloc
    struct RegionalBloc: Codable {
        let acronym, name: String
        let otherAcronyms, otherNames: [JSONAny]
    }

Который предназначен для декодирования только следующего JSON:

"regionalBlocs":[{"acronym":"SAARC","name":"South Asian Association for Regional Cooperation","otherAcronyms":[],"otherNames":[]}]

Есть ли простой способ разобрать вышеописанное, не прибегая к вспомогательным классам буквально с пятнадцатью функциями и методами. Скорее всего, otherAcronyms и otherNames являются строками, поэтому я думаю, что я мог бы использовать [String?]. Тем не менее, я думаю, что не знаю этого со 100% уверенностью, скорее, с 95% уверенностью.

Спасибо за любые предложения.


person user6631314    schedule 28.07.2020    source источник
comment
Каково содержимое массивов otherAcronyms и otherNames?   -  person Joakim Danielson    schedule 28.07.2020
comment
В примерах он пуст, и я думаю, именно поэтому он создал Any. Даже если он должен использовать Any, я удивлен, что Any настолько сложен. Я сделал еще несколько выборочных проверок, и оказалось, что обычно это строка, хотя это может быть строка с другим набором символов, например: جامعة الدول العربية. Как вы думаете, я в порядке с [String?]   -  person user6631314    schedule 28.07.2020
comment
[JSONAny] предоставляется в случае, если входящий формат значения неизвестен.   -  person Frankenstein    schedule 28.07.2020
comment
Да, тогда вы должны быть в порядке с [String] для массива. Нет необходимости в дополнительной строке, если вы не ожидаете фактических значений null/nil.   -  person Joakim Danielson    schedule 28.07.2020
comment
Совет для тех, кто пытается отладить аналогичную проблему и сталкивается с этим вопросом. Возьмите JSON с отсутствующими значениями, скопируйте его в JSONLint, а затем заполните отсутствующие значения, нули и т. д. тем, что вы получили бы, если бы API был полностью заполнен и полностью сформирован. Скопируйте и вставьте этот текст в QuickType, и он даст вам улучшенные предложения для ваших структур. Тогда можно будет тонко настроить. В итоге я использовал опции для отсутствующих значений. Может быть, есть лучший способ, но это сработало для меня.   -  person user6631314    schedule 30.07.2020


Ответы (1)


Если вы уверены, что клавиши otherAcronyms и otherNames возвращают [String?], вы можете изменить структуру RegionalBloc, чтобы принять [String?].

struct RegionalBloc: Codable {
    let acronym, name: String
    let otherAcronyms, otherNames: [String?]
}

Вы можете просто попробовать это, и если JSONDecoder не выдает никаких ошибок, все в порядке, и вы можете продолжить с [String?]. В противном случае вы можете проверить ошибку и распечатать ее на консоли, чтобы проверить входящий тип и установить его.

person Frankenstein    schedule 28.07.2020
comment
Как с [String], так и с [String?] После написания некоторого кода для тестирования, для следующего JSON я получаю следующую ошибку: RegionalBlocs: [{acronym:EU,name:European Union,otherAcronyms:[],otherNames:[] }],cioc:FRA}]} typeMismatch(Swift.Array‹Any›, Swift.DecodingError.Context(codingPath: [], debugDescription: Ожидается декодирование Array‹Any›, но вместо этого найден словарь., baseError: nil)) - person user6631314; 29.07.2020
comment
Как я уже упоминал в ответе, в ошибке четко указано, что входящий тип является словарем. Итак, вы должны предоставить другую кодируемую модель struct вместо [String?] - person Frankenstein; 29.07.2020
comment
По словарю, я думаю, это означает: otherNames:[]. Я знаю, что значение словаря, если оно не пустое, будет массивом из одной или нескольких строк, таких как [Comunidad del Caribe,Communauté Caribéenne], но я думаю, что он этого не знает. Я видел несколько ответов на SO, которые предполагают, что вам нужно использовать свой собственный init(from для обработки пустых массивов. stackoverflow.com/questions/48943510/ - person user6631314; 29.07.2020
comment
Нет, словарь означает [:]. Но в вашем вопросе вы изобразили otherNames как массив, то есть []. - person Frankenstein; 29.07.2020
comment
Это [], а не [:] Фактический JSON — это RegionalBlocs:[{acronym:EU,name:European Union,otherAcronyms:[],otherNames:[]}]. Кажется, это не работает на otherAcronyms: [] Я смог успешно декодировать: {test: []} с помощью let test : [String?], но зашел в тупик на полном примере. Имеет ли значение, что RegionalBlocs кажется массивом элементов, например [{}]? - person user6631314; 29.07.2020
comment
Да, это имеет значение, если вы не укажете правильный тип, ваше декодирование не удастся. Если у вас есть полный пример, используйте его для создания своей модели в быстром типе. Если вы уверены, что это [], то это массив. Но сообщение об ошибке говорит об обратном. - person Frankenstein; 29.07.2020
comment
Я добавил новый уровень для отражения массива, поэтому теперь я использую struct RegionalBlocs: Codable { let RegionalBloc: [RegionalBloc] } struct RegionalBloc: Codable { let acronym, name: String let otherAcronyms, otherNames: [String] } Однако это все еще выдает ту же ошибку. В []. Я проверил это, просто скопировав json в строку, а не в прямом эфире .... Загадочно. Может быть, я удалю все эти вещи из строки. - person user6631314; 29.07.2020
comment
Наконец, он заработал, заполнив все отсутствующие значения в JSON фиктивными значениями, получив улучшенные предложения от быстрого ввода и немного подстроив. - person user6631314; 30.07.2020