Как разобрать вложенные массивы JSON из объекта, возвращенного с помощью запроса Moya.Response - PullRequest
0 голосов
/ 03 апреля 2019

Я пытаюсь проанализировать объект JSON, полученный в результате сетевого сеанса (через MoyaProvider).Возвращенный объект JSON содержит вложенные массивы JSON.Это выглядит примерно так:

Редактировать: Ссылка на файл json находится здесь. results.json

{
“resultCount” : 50,
“results” :
[
    {
        “data1”: 1
        “data2”: 2
    },
    {
        “data1”: 1
        “data2”: 2
    },
    {
        “data1”: 1
        “data2”: 2
    }
]
}

Теперь, используя Мойя, я могу получить данные с помощью API Moya.Response, например:

let jsonObj = try response.mapJSON()

Но яя не хочу этого делать, я хочу отобразить это в моей структуре Model.Я сделал что-то вроде этого ниже.Который я проверил (через OPTION + MouseHover), что objMovie имеет тип [Movie]

let objMovie = try response.map(ITunesSearchResults<Movie>.self).results

Я следовал онлайн-уроку, используя подобную технику, но я не понимаю, почему objMovie не содержит возвратзначения после выполнения строки выше.Я пытался сделать

print(obj.< propertyofMovie >)

, но на консоли ничего не отображается.

Так что же дает?

Вот некоторые фрагменты кода.Где ITunesSearchResults:

struct ITunesSearchResults<T: Decodable>: Decodable {
    let results: [T]
}

И моя структура Кино это.Он соответствует значениям ключа, найденным в свойствах вложенного массива JSON.

struct Movie: Codable
{
   let trackId: Int
   let trackName: String
   let trackGenre: String
   let trackPrice: Int?
   let longDescription: String

   init(trackId: Int, trackName: String, trackGenre: String, 
   trackPrice: 
   Int?, /*trackImage: Thumbnail,*/ longDescription: String)
   {
    self.trackId = trackId
    self.trackName = trackName
    self.trackGenre = trackGenre
    self.trackPrice = trackPrice ?? 0
    self.longDescription = longDescription
    //self.trackImage = trackImage //TODO: thumbnail: mapp url from json
   }

  private enum MovieCodingKeys: String, CodingKey
  {
    case trackId
    case trackName
    case trackGenre = "primaryGenreName"
    case trackPrice
    //case trackImage
    case longDescription
  }

  init(from decoder: Decoder) throws
  {
    let container = try decoder.container(keyedBy: MovieCodingKeys.self)

    trackId = try container.decode(Int.self, forKey: .trackId)
    trackName = try container.decode(String.self, forKey: .trackName)
    trackGenre = try container.decode(String.self, forKey: .trackGenre)
    trackPrice = try container.decode(Int?.self, forKey: .trackPrice)
    longDescription = try container.decode(String.self, forKey: .longDescription)
  }
}

1 Ответ

0 голосов
/ 03 апреля 2019

Прежде всего используйте Data ответ Moya, так как вы делаете хотите декодировать JSON с помощью Decodable, например

let data = response.data

Ваша Movie структура слишком сложная, явная CodingKeys и метод init вообще не нужен, вы получаете их бесплатно. Этого достаточно:

struct ITunesSearchResults<T: Decodable>: Decodable {
    let results: [T]
}

struct Movie: Decodable
{
    let trackId: Int
    let trackName: String
    let trackGenre: String?
    let trackPrice: Double?
    let longDescription: String
}

Обратите внимание, что trackPrice - это Double, а trackGenre и trackPrice являются необязательными.

Теперь декодируем просто

do {
    let result = try JSONDecoder().decode(ITunesSearchResults<Movie>.self, from: data)
    print(result)
} catch { print(error) }

Примечание:

Никогда использовать такой синтаксис, как

try container.decode(Int?.self, forKey: .trackPrice)

Есть decodeIfPresent

try container.decodeIfPresent(Int.self, forKey: .trackPrice)

Огромным преимуществом является то, что он выдает ошибку, если ключ присутствует, но тип неправильный, как в данном конкретном случае.

...