2017-10-13 1 views
0

En apprenant les API et les Decodable actuellement et pour la pratique, j'ai voulu essayer d'imprimer le nom de chaque événement sur Ticketmaster en utilisant leur API. Avec toute tentative de, Im obtenir cette erreur qui m'a été présentée:Extraire des données de l'API TicketMasters (Swift 4.0/Decodable)

Error serializing JSON: typeMismatch(Swift.Array<Any>, Swift.DecodingError.Context(codingPath: [], debugDescription: "Expected to decode Array<Any> but found a dictionary instead.", underlyingError: nil)) 

Que Im essayant de faire est d'imprimer juste les noms des événements dans la région de débogage, mais rien ne montre vers le haut. J'ai un struct suivant le protocole décodable nommé Événements:

struct Event: Decodable { 
let name: String? } 

Et ma tentative de demander les informations de Ticketmaster en utilisant ma clé API:

//API String Request 
    let jsonUrlString = "https://app.ticketmaster.com/discovery/v2/events.json?countryCode=US&apikey=zqqqmkCdkfslHeaCvqXbxQZFGNXHoAT2" 
    guard let url = URL(string: jsonUrlString) else { return } 

    //Method to pull information from Ticketmasters API 
    URLSession.shared.dataTask(with: url) { (data, response, err) in 
     guard let data = data else { return } 
     let dataAsString = String(data: data, encoding: .utf8) 
     print(dataAsString) 

     do { 
      let events = try JSONDecoder().decode([Event].self, from: data) 
      print(events) 
      print() 
      print("Done.") 
     } catch let jsonErr { 
      print("Error serializing JSON:", jsonErr) 
     } 
    }.resume() 

Qu'est-ce que je fais mal? C'est saisir les données correctement, ce que je peux dire à cause de l'instruction d'impression que j'ai (print (dataAsString)), mais quand je veux juste afficher les noms, Im obtenir l'erreur.

Voici une image de la structure de données pour référence. Est-ce à cause de la partie embarquée? Toute aide serait vraiment appréciée!

enter image description here

Répondre

3

I généré Codables pour la réponse API TicketMaster en utilisant quicktype:

typealias TicketMaster = OtherTicketMaster 

struct OtherTicketMaster: Codable { 
    let links: OtherOtherLinks 
    let embedded: Embedded 
    let page: Page 
} 

struct OtherOtherLinks: Codable { 
    let last: OtherAttraction 
    let first: OtherAttraction 
    let next: OtherAttraction 
    let otherSelf: OtherAttraction 
} 

struct OtherAttraction: Codable { 
    let href: String 
} 

struct Embedded: Codable { 
    let events: [Event] 
} 

struct Event: Codable { 
    let info: String? 
    let classifications: [Classification] 
    let links: OtherLinks 
    let embedded: OtherEmbedded 
    let accessibility: Accessibility? 
    let id: String 
    let dates: Dates 
    let images: [Image] 
    let priceRanges: [PriceRange] 
    let sales: Sales 
    let name: String 
    let locale: String 
    let pleaseNote: String? 
    let promoter: Promoter 
    let products: [Products]? 
    let promoters: [Promoter] 
    let test: Bool 
    let seatmap: Seatmap 
    let type: String 
    let url: String 
} 

struct Classification: Codable { 
    let primary: Bool 
    let subGenre: Genre 
    let genre: Genre 
    let segment: Genre 
    let subType: Genre 
    let type: Genre 
} 

struct Genre: Codable { 
    let id: String 
    let name: String 
} 

struct OtherLinks: Codable { 
    let otherSelf: OtherAttraction 
    let attractions: [OtherAttraction] 
    let venues: [OtherAttraction] 
} 

struct OtherEmbedded: Codable { 
    let attractions: [Attraction] 
    let venues: [Venue] 
} 

struct Attraction: Codable { 
    let images: [Image] 
    let classifications: [Classification] 
    let links: Links 
    let id: String 
    let name: String 
    let type: String 
    let locale: String 
    let test: Bool 
    let upcomingEvents: UpcomingEvents 
    let url: String 
} 

struct Links: Codable { 
    let otherSelf: OtherAttraction 
} 

struct UpcomingEvents: Codable { 
    let ticketmaster: Int? 
    let total: Int 
    let tmr: Int? 
} 

struct Venue: Codable { 
    let generalInfo: GeneralInfo? 
    let postalCode: String 
    let boxOfficeInfo: BoxOfficeInfo? 
    let accessibleSeatingDetail: String? 
    let links: Links 
    let address: Address 
    let country: Country 
    let city: City 
    let dmas: [Dma] 
    let location: Location 
    let images: [Image]? 
    let id: String 
    let locale: String 
    let name: String 
    let markets: [Market] 
    let parkingDetail: String 
    let timezone: String 
    let state: State 
    let social: Social? 
    let test: Bool 
    let upcomingEvents: UpcomingEvents 
    let type: String 
    let url: String 
} 

struct GeneralInfo: Codable { 
    let childRule: String? 
    let generalRule: String 
} 

struct BoxOfficeInfo: Codable { 
    let openHoursDetail: String 
    let acceptedPaymentDetail: String 
    let phoneNumberDetail: String? 
    let willCallDetail: String 
} 

struct Address: Codable { 
    let line1: String 
} 

struct Country: Codable { 
    let countryCode: String 
    let name: String 
} 

struct City: Codable { 
    let name: String 
} 

struct Dma: Codable { 
    let id: Int 
} 

struct Location: Codable { 
    let latitude: String 
    let longitude: String 
} 

struct Market: Codable { 
    let id: String 
} 

struct State: Codable { 
    let name: String 
    let stateCode: String 
} 

struct Social: Codable { 
    let twitter: Twitter 
} 

struct Twitter: Codable { 
    let handle: String 
} 

struct Accessibility: Codable { 
    let info: String 
} 

struct Dates: Codable { 
    let start: Start 
    let spanMultipleDays: Bool 
    let status: Status 
    let timezone: String 
} 

struct Start: Codable { 
    let localDate: String 
    let dateTBD: Bool 
    let dateTBA: Bool 
    let dateTime: String 
    let noSpecificTime: Bool 
    let localTime: String 
    let timeTBA: Bool 
} 

struct Status: Codable { 
    let code: String 
} 

struct Image: Codable { 
    let fallback: Bool 
    let ratio: String? 
    let attribution: String? 
    let height: Int 
    let url: String 
    let width: Int 
} 

struct PriceRange: Codable { 
    let max: Double 
    let currency: String 
    let min: Double 
    let type: String 
} 

struct Sales: Codable { 
    let presales: [Presales]? 
    let otherPublic: Public 
} 

struct Presales: Codable { 
    let endDateTime: String 
    let startDateTime: String 
    let description: String? 
    let name: String 
    let url: String? 
} 

struct Public: Codable { 
    let startDateTime: String 
    let endDateTime: String 
    let startTBD: Bool 
} 

struct Promoter: Codable { 
    let id: String 
    let description: String 
    let name: String 
} 

struct Products: Codable { 
    let name: String 
    let id: String 
    let type: String 
    let url: String 
} 

struct Seatmap: Codable { 
    let staticUrl: String 
} 

struct Page: Codable { 
    let size: Int 
    let number: Int 
    let totalElements: Int 
    let totalPages: Int 
} 

// Serialization extensions 

extension OtherTicketMaster { 
    static func from(json: String, using encoding: String.Encoding = .utf8) -> OtherTicketMaster? { 
     guard let data = json.data(using: encoding) else { return nil } 
     return OtherTicketMaster.from(data: data) 
    } 

    static func from(data: Data) -> OtherTicketMaster? { 
     let decoder = JSONDecoder() 
     return try? decoder.decode(OtherTicketMaster.self, from: data) 
    } 

    var jsonData: Data? { 
     let encoder = JSONEncoder() 
     return try? encoder.encode(self) 
    } 

    var jsonString: String? { 
     guard let data = self.jsonData else { return nil } 
     return String(data: data, encoding: .utf8) 
    } 
} 

extension Accessibility { 
    enum CodingKeys: String, CodingKey { 
     case info 
    } 
} 

extension Address { 
    enum CodingKeys: String, CodingKey { 
     case line1 
    } 
} 

extension Attraction { 
    enum CodingKeys: String, CodingKey { 
     case images 
     case classifications 
     case links = "_links" 
     case id 
     case name 
     case type 
     case locale 
     case test 
     case upcomingEvents 
     case url 
    } 
} 

extension BoxOfficeInfo { 
    enum CodingKeys: String, CodingKey { 
     case openHoursDetail 
     case acceptedPaymentDetail 
     case phoneNumberDetail 
     case willCallDetail 
    } 
} 

extension City { 
    enum CodingKeys: String, CodingKey { 
     case name 
    } 
} 

extension Classification { 
    enum CodingKeys: String, CodingKey { 
     case primary 
     case subGenre 
     case genre 
     case segment 
     case subType 
     case type 
    } 
} 

extension Country { 
    enum CodingKeys: String, CodingKey { 
     case countryCode 
     case name 
    } 
} 

extension Dates { 
    enum CodingKeys: String, CodingKey { 
     case start 
     case spanMultipleDays 
     case status 
     case timezone 
    } 
} 

extension Dma { 
    enum CodingKeys: String, CodingKey { 
     case id 
    } 
} 

extension Embedded { 
    enum CodingKeys: String, CodingKey { 
     case events 
    } 
} 

extension Event { 
    enum CodingKeys: String, CodingKey { 
     case info 
     case classifications 
     case links = "_links" 
     case embedded = "_embedded" 
     case accessibility 
     case id 
     case dates 
     case images 
     case priceRanges 
     case sales 
     case name 
     case locale 
     case pleaseNote 
     case promoter 
     case products 
     case promoters 
     case test 
     case seatmap 
     case type 
     case url 
    } 
} 

extension GeneralInfo { 
    enum CodingKeys: String, CodingKey { 
     case childRule 
     case generalRule 
    } 
} 

extension Genre { 
    enum CodingKeys: String, CodingKey { 
     case id 
     case name 
    } 
} 

extension Image { 
    enum CodingKeys: String, CodingKey { 
     case fallback 
     case ratio 
     case attribution 
     case height 
     case url 
     case width 
    } 
} 

extension Links { 
    enum CodingKeys: String, CodingKey { 
     case otherSelf = "self" 
    } 
} 

extension Location { 
    enum CodingKeys: String, CodingKey { 
     case latitude 
     case longitude 
    } 
} 

extension Market { 
    enum CodingKeys: String, CodingKey { 
     case id 
    } 
} 

extension OtherAttraction { 
    enum CodingKeys: String, CodingKey { 
     case href 
    } 
} 

extension OtherEmbedded { 
    enum CodingKeys: String, CodingKey { 
     case attractions 
     case venues 
    } 
} 

extension OtherLinks { 
    enum CodingKeys: String, CodingKey { 
     case otherSelf = "self" 
     case attractions 
     case venues 
    } 
} 

extension OtherOtherLinks { 
    enum CodingKeys: String, CodingKey { 
     case last 
     case first 
     case next 
     case otherSelf = "self" 
    } 
} 

extension OtherTicketMaster { 
    enum CodingKeys: String, CodingKey { 
     case links = "_links" 
     case embedded = "_embedded" 
     case page 
    } 
} 

extension Page { 
    enum CodingKeys: String, CodingKey { 
     case size 
     case number 
     case totalElements 
     case totalPages 
    } 
} 

extension Presales { 
    enum CodingKeys: String, CodingKey { 
     case endDateTime 
     case startDateTime 
     case description 
     case name 
     case url 
    } 
} 

extension PriceRange { 
    enum CodingKeys: String, CodingKey { 
     case max 
     case currency 
     case min 
     case type 
    } 
} 

extension Products { 
    enum CodingKeys: String, CodingKey { 
     case name 
     case id 
     case type 
     case url 
    } 
} 

extension Promoter { 
    enum CodingKeys: String, CodingKey { 
     case id 
     case description 
     case name 
    } 
} 

extension Public { 
    enum CodingKeys: String, CodingKey { 
     case startDateTime 
     case endDateTime 
     case startTBD 
    } 
} 

extension Sales { 
    enum CodingKeys: String, CodingKey { 
     case presales 
     case otherPublic = "public" 
    } 
} 

extension Seatmap { 
    enum CodingKeys: String, CodingKey { 
     case staticUrl 
    } 
} 

extension Social { 
    enum CodingKeys: String, CodingKey { 
     case twitter 
    } 
} 

extension Start { 
    enum CodingKeys: String, CodingKey { 
     case localDate 
     case dateTBD 
     case dateTBA 
     case dateTime 
     case noSpecificTime 
     case localTime 
     case timeTBA 
    } 
} 

extension State { 
    enum CodingKeys: String, CodingKey { 
     case name 
     case stateCode 
    } 
} 

extension Status { 
    enum CodingKeys: String, CodingKey { 
     case code 
    } 
} 

extension Twitter { 
    enum CodingKeys: String, CodingKey { 
     case handle 
    } 
} 

extension UpcomingEvents { 
    enum CodingKeys: String, CodingKey { 
     case ticketmaster 
     case total = "_total" 
     case tmr 
    } 
} 

extension Venue { 
    enum CodingKeys: String, CodingKey { 
     case generalInfo 
     case postalCode 
     case boxOfficeInfo 
     case accessibleSeatingDetail 
     case links = "_links" 
     case address 
     case country 
     case city 
     case dmas 
     case location 
     case images 
     case id 
     case locale 
     case name 
     case markets 
     case parkingDetail 
     case timezone 
     case state 
     case social 
     case test 
     case upcomingEvents 
     case type 
     case url 
    } 
} 

// Helpers 

class JSONNull: Codable { 
    public init() { 
    } 

    public required init(from decoder: Decoder) throws { 
     let container = try decoder.singleValueContainer() 
     if !container.decodeNil() { 
      throw DecodingError.typeMismatch(JSONNull.self, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Wrong type for JSONNull")) 
     } 
    } 

    public func encode(to encoder: Encoder) throws { 
     var container = encoder.singleValueContainer() 
     try container.encodeNil() 
    } 
} 

Vous verrez que le type de haut niveau de la réponse JSON n'est pas [Event], mais un objet de type TicketMaster, qui a une valeur [Event] imbriquée à .embedded.events. Voici comment obtenir les noms de tous les événements:

let ticketMaster = TicketMaster.from(json: dataAsString)! 
let eventNames = ticketMaster.embedded.events.map { $0.name } 
+0

NICE RÉPONSE! Utilitaire de sauvetage. – Jeff