Search code examples
swiftencodable

Why not conform to protocol encodable decodable?


I have the following structure of code. If I omit the codingkey part the code is running. I implemented StringConverter to convert a string to Int (from bySundell Swift Side)

struct Video: Codable {
    var title: String
    var description: String
    var url: URL
    var thumbnailImageURL: URL

    var numberOfLikes: Int {
        get { return likes.value }

    }

    private var likes: StringBacked<Int>
    enum CodingKeys: String, CodingKey{
        case title = "xxx"
        case description = "jjjj"
        case url = "url"
        case thumbnailImageURL = "jjjjjjjj"
        case numberofLikes = "jjjjjkkkk"

    }

}


// here the code for converting the likes
protocol StringRepresentable: CustomStringConvertible {
    init?(_ string: String)
}

extension Int: StringRepresentable {}
struct StringBacked<Value: StringRepresentable>: Codable {
    var value: Value

    init(from decoder: Decoder) throws {
        let container = try decoder.singleValueContainer()
        let string = try container.decode(String.self)
        let stringToConvert = string.split(separator: "/").last!.description
        guard let value = Value(stringToConvert) else {
            throw DecodingError.dataCorruptedError(
                in: container,
                debugDescription: """
                Failed to convert an instance of \(Value.self) from "\(string)"
                """
            )
        }

        self.value = value
    }

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

As i said, if I omit the Codingkeys part it does me show no error. I would simply create a struct, where I get a string from a Rest API and I want to convert in an Int for my database using Codable. Thanks Arnold


Solution

  • When you define CodingKeys, you need to provide key for each non-optional/non-initialized property so that compiler know how to initialize while decoding. Applying this to Video, it will look like this,

    struct Video: Codable {
    
        var title: String
        var description: String
        var url: URL
        var thumbnailImageURL: URL
    
        var numberOfLikes: Int {
            return likes.value
    
        }
    
        private var likes: StringBacked<Int>
    
        enum CodingKeys: String, CodingKey{
            case title = "xxx"
            case description = "jjjj"
            case url = "url"
            case thumbnailImageURL = "jjjjjjjj"
            case likes = "jjjjjkkkk"
    
        }
    }
    

    If you see closely, this property private var likes: StringBacked<Int> was not provided any CodingKey in the enum so compiler was complaining. I updated the enum with this case case likes = "jjjjjkkkk" and removed case numberofLikes = "jjjjjkkkk" because numberofLikes is a read only computed property that doesn't need any parsing.