3

I'm attempting to parse the following json schema, poster may or may not be empty

{
  "poster": {},
  "recommends": []
}

My decodable classes are as follows:

public struct RecommendedList: Decodable {
    public let poster: Poster?
    public let recommends: [Recommend]
}

public struct Poster: Decodable {
    public let backgroundImage: URL
    public let topImage: URL
    public let windowImage: URL
    public let windowSkinImagePath: URL
    public let deeplink: URL

    public init(from decoder: Decoder) throws {
        // I want a failable intializer not one that throws
    }
}

My question is how do I make poster optional? My thought was I would need a failable initializer, but decodable requires a init that throws.

rmaddy
  • 314,917
  • 42
  • 532
  • 579
Cory
  • 2,302
  • 20
  • 33
  • 1
    Don't fight the framework. Use the `throw`ing initializer. The optional property is suffcient – vadian Dec 01 '17 at 17:54
  • Throwing IS the way to have the initializer fail. If your `init` throws then you set your `poster` property to `nil`. – creeperspeak Dec 01 '17 at 17:56
  • @creeperspeak Thanks, I was over thinking this completely. – Cory Dec 01 '17 at 18:00
  • @creeperspeak I must be missing something obvious because if poster is empty like above, I get a parsing error, not a nil optional like I'm hoping `Key Not Found => No value associated with key backgroundImage ("bgimage")` – Cory Dec 01 '17 at 18:15
  • marking your structures, its properties and initializer with public is redundant – Leo Dabus Dec 01 '17 at 18:35
  • @vadian what if I have a `[Codable]` property? – zrslv Aug 01 '18 at 07:18
  • @zrxq I don't understand. – vadian Aug 01 '18 at 07:20
  • @vadian Lets say I'm decoding an array of `Codable`. In this case, `throw`ing from single element's `init` isn't an option, it will fail the entire array. – zrslv Aug 01 '18 at 07:24
  • You can't use `Codable` as a type anyway. A protocol cannot conform to itself. – vadian Aug 01 '18 at 07:29
  • @vadian An object of a class, conforming to `Codable` is also a `Codable`, and yes, you can have a `[Codable]` property in your struct/class/whatever. Okay, I think we are discussing a question that is already answered (kinda) here: https://stackoverflow.com/questions/46344963/swift-jsondecode-decoding-arrays-fails-if-single-element-decoding-fails – zrslv Aug 01 '18 at 07:37
  • @zrxq Please see also https://stackoverflow.com/questions/45053060/using-jsonencoder-to-encode-a-variable-with-codable-as-type – vadian Aug 01 '18 at 14:00

1 Answers1

2

so it looks like I needed to add a try? in the Recommended List init(from decoder:)

public struct RecommendedList: Decodable {
    public let poster: Poster?
    public let recommends: [Recommend]

    enum CodingKeys: String, CodingKey {
        case poster
        case recommends
    }

    public init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        poster = try? container.decode(Poster.self, forKey: .poster)
        recommends = try container.decode([Recommend].self, forKey: .recommends)
    }
}
Cory
  • 2,302
  • 20
  • 33