Я делаю несколько вызовов в API Apple Music, который возвращает массив ресурсов объектов. Объект Resource имеет свойство, называемое атрибутами объекта типа, которое зависит от того, является ли это Song , Playlist или Album .
Как мне смоделировать объект ресурса, чтобы я мог декодировать JSON и создавать объекты Song, Playlist и Album?
struct Resource {
let id : String?
let type : String?
let href : String?
let attributes : "What goes here?"
}
Обновление 1:
Я попробовал вторую рекомендацию Джо и настроил свои структуры так:
struct Resource: Decodable{
enum Attribute {
case song(Song), playlist(Playlist)
}
let id : String?
let type : String?
let href : String?
let attributes: Attribute?
enum CodingKeys : CodingKey{
case id, type, href, attributes
}
init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
id = try values.decode(String.self, forKey: .id)
type = try values.decode(String.self, forKey: .type)
href = try values.decode(String.self, forKey: .href)
switch type {
case "library-songs":
attributes = try .song(values.decode(Song.self, forKey: .attributes))
case "library-playlists":
attributes = try .playlist(values.decode(Playlist.self, forKey: .attributes))
default:
attributes = nil
}
}
}
struct Song : Decodable {
let playParams : PlayParams?
let trackNumber : Int?
let durationInMillis : Int?
let name : String?
let albumName : String?
let artwork : Artwork?
let contentRating : String?
let artistName : String?
}
struct Artwork : Decodable {
let width : Int?
let height : Int?
let url : String?
}
struct PlayParams : Decodable {
let id : String?
let kind : String?
let isLibrary : Bool?
}
Пример JSON выглядит следующим образом для песни:
{
"data": [
{
"id": "i.4YBNbl3IXVJQRM",
"type": "library-songs",
"href": "/v1/me/library/songs/i.4YBNbl3IXVJQRM",
"attributes": {
"albumName": "\"Awaken, My Love!\"",
"artwork": {
"width": 1200,
"height": 1200,
"url": "https://is5-ssl.mzstatic.com/image/thumb/Music71/v4/00/d0/d7/00d0d743-b0de-31d8-09eb-0796269bb555/UMG_cvrart_00044003187658_01_RGB72_1800x1800_16UMGIM77118.jpg/{w}x{h}bb.jpg"
},
"durationInMillis": 326933,
"playParams": {
"id": "i.4YBNbl3IXVJQRM",
"kind": "song",
"isLibrary": true
},
"artistName": "Childish Gambino",
"trackNumber": 6,
"name": "Redbone",
"contentRating": "explicit"
}
},
{
"id": "i.mmpeOrZiLqoKOv",
"type": "library-songs",
"href": "/v1/me/library/songs/i.mmpeOrZiLqoKOv",
"attributes": {
"albumName": "Funk Wav Bounces Vol. 1",
"artwork": {
"width": 1200,
"height": 1200,
"url": "https://is5-ssl.mzstatic.com/image/thumb/Music127/v4/8b/37/23/8b372308-f764-d03a-5bda-a7a456292547/886446469607.jpg/{w}x{h}bb.jpg"
},
"durationInMillis": 272659,
"playParams": {
"id": "i.mmpeOrZiLqoKOv",
"kind": "song",
"isLibrary": true
},
"artistName": "Calvin Harris",
"trackNumber": 4,
"name": "Rollin (feat. Future & Khalid)",
"contentRating": "explicit"
}
},
{
"id": "i.JL1aVxNtzmYDJG",
"type": "library-songs",
"href": "/v1/me/library/songs/i.JL1aVxNtzmYDJG",
"attributes": {
"albumName": "The Weekend (Funk Wav Remix) - Single",
"artwork": {
"width": 1200,
"height": 1200,
"url": "https://is4-ssl.mzstatic.com/image/thumb/Music118/v4/aa/d5/e5/aad5e5e3-dff5-7d8f-5747-b695ad9f2299/886446852157.jpg/{w}x{h}bb.jpg"
},
"durationInMillis": 171806,
"playParams": {
"id": "i.JL1aVxNtzmYDJG",
"kind": "song",
"isLibrary": true
},
"artistName": "SZA & Calvin Harris",
"trackNumber": 1,
"name": "The Weekend (Funk Wav Remix)"
}
}
]
}
Когда я декодирую данные, используя:
let resource = try? JSONDecoder().decode([Resource].self, from: data!)
print(resource!)
Я получаю фатальную ошибку: неожиданно обнаружил ноль при развертывании необязательного значения
Обновление 2:
Я понял проблему. Дополнительный слой сверху испортил декодирование. Я добавил еще один уровень:
struct Welcome: Codable {
let data: [Datum]
}
struct Datum: Codable {
let id, type, href: String
let attributes: Attributes
}
struct Attributes: Codable {
let albumName: String
let artwork: Artwork
let durationInMillis: Int
let playParams: PlayParams
let artistName: String
let trackNumber: Int
let name: String
let contentRating: String?
}
struct Artwork: Codable {
let width, height: Int
let url: String
}
struct PlayParams: Codable {
let id, kind: String
let isLibrary: Bool
}
Это работает только для песен, но я постараюсь переопределить как песни, так и плейлисты.