【问题标题】:Codable Parsing issue可编码解析问题
【发布时间】:2023-03-12 10:23:01
【问题描述】:

我正在尝试使用 Codable 类解析 API 响应。

下面是回复:

{"status":200,"message":"","success":1,"data":[{"event_id":"26","event_name":"Mens Night","event_desc":"Hot Mens Night","from_date":"2019-02-08","to_date":"2019-03-09","bar_id":"62","bar_names":"Autumn Bar & Bistro","bar_ids":"62","offer_image":"https:\/\/www.tippler.app\/manager\/uploads\/events\/mens_night.jpg","from_time":"19:00:00","to_time":"01:30:00"},{"event_id":"36","event_name":"Karaoke Night","event_desc":"Karaoke NIght with Brian Rub","from_date":"2019-02-08","to_date":"2019-02-09","bar_id":"146","bar_names":"Amuse Resto Bar","bar_ids":"146","offer_image":"https:\/\/www.tippler.app\/manager\/uploads\/events\/Screenshot_20190208-155223__011.jpg","from_time":"21:00:00","to_time":"01:00:00"},{"event_id":"37","event_name":"Sufi Nights","event_desc":"Singers From mumbai","from_date":"2019-02-08","to_date":"2019-02-09","bar_id":"66","bar_names":"Cavalry The Lounge","bar_ids":"66","offer_image":"https:\/\/www.tippler.app\/manager\/uploads\/events\/SUFI-FEATURED.jpg","from_time":"20:00:00","to_time":"01:30:00"},{"event_id":"39","event_name":"BOLLYWOOD NIGHT","event_desc":"BHANGRA AND LIVE DHOL","from_date":"2019-02-09","to_date":"2019-02-10","bar_id":"103","bar_names":"B Desi","bar_ids":"103","offer_image":"https:\/\/www.tippler.app\/manager\/uploads\/events\/bollywood-nights-1.jpg","from_time":"21:00:00","to_time":"01:00:00"}],"error_dev":""}

I Codable 类是:

struct Events: Codable {
    var event_id: String
    var event_name: String
    var event_desc: String
    var from_date: String
    var to_date: String
    var bar_id: String
    var bar_names: String
    var bar_ids: String
    var offer_image: String
    var from_time: String
    var to_time: String

    enum CodingKeys: String, CodingKey {
        case event_id = "event_id"
        case event_name = "event_name"
        case event_desc = "event_desc"
        case from_date = "from_date"
        case to_date = "to_date"
        case bar_id = "bar_id"
        case bar_names = "bar_names"
        case bar_ids = "bar_ids"
        case offer_image = "offer_image"
        case from_time = "from_time"
        case to_time = "to_time"
    }

    func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: CodingKeys.self)
        try container.encode(event_id, forKey: .event_id)
        try container.encode(event_name, forKey: .event_name)
        try? container.encode(event_desc, forKey: .event_desc)
        try? container.encode(from_date, forKey: .from_date)
        try container.encode(to_date, forKey: .to_date)
        try container.encode(bar_id, forKey: .bar_id)
        try container.encode(bar_names, forKey: .bar_names)
        try container.encode(bar_ids, forKey: .bar_ids)
        try container.encode(offer_image, forKey: .offer_image)
        try container.encode(from_time, forKey: .from_time)
        try container.encode(to_time, forKey: .to_time)
    }


    init(from decoder: Decoder) throws {
        let values = try decoder.container(keyedBy: CodingKeys.self)
        event_id = try values.decode(String.self, forKey: .event_id)
        event_name = try values.decode(String.self, forKey: .event_name)
        event_desc = try values.decode(String.self, forKey: .event_desc)
        from_date = try values.decode(String.self, forKey: .from_date)
        to_date = try values.decode(String.self, forKey: .to_date)
        bar_id = try values.decode(String.self, forKey: .bar_id)
        bar_names = try values.decode(String.self, forKey: .bar_names)
        bar_ids = try values.decode(String.self, forKey: .bar_ids)
        offer_image = try values.decode(String.self, forKey: .offer_image)
        from_time = try values.decode(String.self, forKey: .from_time)
        to_time = try values.decode(String.self, forKey: .to_time)
    }


}

它正在返回响应错误

keyNotFound(CodingKeys(stringValue: "event_id", intValue: nil), Swift.DecodingError.Context(编码路径: [编码键>(字符串值:“数据”,intValue:无), _JSONKey(stringValue: "Index 0", intValue: 0)], debugDescription: "No value associated with key CodingKeys(stringValue: \"event_id\", intValue: nil) (\"event_id\").", underlyingError: nil))

请给我建议解决方案。

【问题讨论】:

    标签: json swift codable


    【解决方案1】:

    您的可编码结构与响应不匹配,因为它们具有状态、消息成功和 errorDev 键

    试试这个

    struct Response: Codable {
        let status: Int?
        let message: String?
        let success: Int?
        let data: [Events]?
        let errorDev: String?
    
        enum CodingKeys: String, CodingKey {
            case status, message, success, data
            case errorDev = "error_dev"
        }
    }
    struct Events: Codable {
        let eventID, eventName, eventDesc, fromDate: String?
        let toDate, barID, barNames, barIDs: String?
        let offerImage: String?
        let fromTime, toTime: String?
    
        enum CodingKeys: String, CodingKey {
            case eventID = "event_id"
            case eventName = "event_name"
            case eventDesc = "event_desc"
            case fromDate = "from_date"
            case toDate = "to_date"
            case barID = "bar_id"
            case barNames = "bar_names"
            case barIDs = "bar_ids"
            case offerImage = "offer_image"
            case fromTime = "from_time"
            case toTime = "to_time"
        }
    }
    

    编辑

    我可以为您提供更通用的解决方案。假设所有 API 都具有相同的响应,但只有 data 键不同

    struct GeneralResponse<T:Codable>: Codable {
         let status: Int?
         let message: String?
         let success: Int?
         let data: T?
         let errorDev: String?
    
        enum CodingKeys: String, CodingKey {
            case message = "msg"
            case code = "code"
            case data = "data" 
          // add more keys
        }
    
        public init(from decoder:Decoder) throws {
            let contaienr = try  decoder.container(keyedBy: CodingKeys.self)
            message = try contaienr.decode(String.self, forKey: .message)
            // Decode Other keys 
    
            do {
                let object = try contaienr.decodeIfPresent(T.self, forKey: .data)
                data = object
    
            } catch {
                data = nil
            }
    
        }
    
    }
    

    现在你可以回复每一个回复

    使用GenericResponse&lt;[Event]&gt;GenericResponse&lt;Login&gt;GenericResponse&lt;[UserList]&gt;

    希望对你有帮助

    【讨论】:

    • 所有 结构成员示意性地声明为可选是一个非常糟糕的建议。
    • @vadian 我不明白为什么,请你解释一下
    • API 发送的 JSON 实际上是一种非常可靠的格式。因此,首先您应该将所有结构成员声明为非可选,并通过将类型更改为可选来捕获并修复可能丢失的键的错误。另一方面,如果一切都是可选的并且出现问题,您将什么也看不到并且您不知道为什么。并且解包永远不会 nil 的选项非常烦人。
    • @vadian 是的,我明白这一点。我更喜欢使用可选的,因为 API 有可能没有发送参数(null),所以我没有处理错误,而是让可编码继续使用可选或 nil 值。后来我用必填字段处理这个。还有一件事是 API 可能包含许多不必要的字段,因此处理每个字段可能太长。并且可选,我们保证应用程序永远不会崩溃。
    【解决方案2】:
    struct Events : Codabel {
       let status: Int?
       let message: String?
       let success: Int?
       let data: [Event]?
       let errorDev: String?
    }
    
    struct Datum: Codable {
        let eventID, eventName, eventDesc, fromDate, offerImage, fromTime, toTime : String?
        let toDate, barID, barNames, barIDs: String?
    }
    

    无需为蛇类写下 CodingKeys,

    解码时,你只需写

    let decoder = JSONDecoder()
    decoder.keyDecodingStrategy = .convertFromSnakeCase
    let responseModel = try decoder.decode(Events.self, from: data) // data from response 
    

    【讨论】:

    • 所有 结构成员示意性地、轻率地声明为可选是一个非常糟糕的建议。
    • 它返回 eventID 和 barID 为 nil
    【解决方案3】:

    您的代码中有几个错误如下...

    • event_id 在您的代码中属于 String 类型,但属于 Int 类型。
    • bar_id 在您的代码中属于 String 类型,但属于 Int 类型。
    • bar_ids 在您的代码中属于 String 类型,但属于 Int 类型。

    您需要更正这些变量类型。

    注意:无论您在哪里找到一个数字,它都会是 Int 类型,一个带有小数点的数字,例如 12.123 然后如果默认情况下将是 Double 类型。在swift中直接假设它是字符串是不可接受的。

    【讨论】:

      猜你喜欢
      • 2014-06-28
      • 2023-04-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-11-20
      • 2016-01-12
      • 1970-01-01
      相关资源
      最近更新 更多