arrays - 从 TicketMasters API 中提取数据 (Swift 4.0/Decodable)

标签 arrays json swift api dictionary

我目前正在学习 API 和 Decodable,为了练习,我想尝试使用他们的 API 打印出 Ticketmaster 上每个事件的名称。每次尝试时,我都会收到此错误:

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

我想做的是在调试区域只打印出事件的名称,但什么也没有显示。我有一个遵循名为 Events 的可解码协议(protocol)的结构:

struct Event: Decodable {
let name: String? }

我尝试使用我的 API key 向 Ticketmaster 请求信息:

//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()

我做错了什么?它正确地抓取了数据,我可以通过打印语句 (print(dataAsString)) 看出这一点,但是当我只想显示名称时,我收到了错误。

这是数据结构的图像以供引用。是因为嵌入部分吗?非常感谢任何帮助!

enter image description here

最佳答案

我使用 quicktype 为 TicketMaster API 响应生成了 Codables :

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()
    }
}

您会看到 JSON 响应的顶级类型不是 [Event],而是一个 TicketMaster 类型的对象,它有一个 [Event] 值嵌套在 .embedded.events 中。以下是获取所有事件名称的方法:

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

关于arrays - 从 TicketMasters API 中提取数据 (Swift 4.0/Decodable),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46738857/

相关文章:

javascript - 我的数组旋转算法有什么问题?

javascript - 函数返回两个数字,并将其保存到变量中

ios - 如何找出这些错误。我的应用程序崩溃了 6 次(来自应用程序分析的报告)?

ios - 如何使用自动布局以编程方式快速设置旋转时 UICollectionView 的宽度

c++ - 二维数组

javascript - AJAX 请求有效负载未显示在控制台日志中

c# - 在 asp.mvc 和 json 中将枚举作为字符串返回

ios - 为 UIImagePicker 添加圆形裁剪组件?

快速移动文本字段问题

javascript - Javascript 获取所有选定选项的结果