Search code examples
iosswiftcodabledecodableencodable

Issue in making a struct Codable


I have Application protocol with 2 variables. And I have component struct that has a variable, which confirms to Application protocol. I need to save this struct in disk . So I'm confirming it to Codable protocol. While doing so I'm getting an error like this ,

"Protocol type 'Application' cannot conform to 'Decodable' because only concrete types can conform to protocols"

Here is my code,

public protocol Application {
     var name : String {get}
     var ownerName : String {get}
}

public struct component : Codable {
     let application : Application
     private enum CodingKeys: String, CodingKey {
           case application
       }

public init(from decoder: Decoder) throws {
        let values = try decoder.container(keyedBy: CodingKeys.self)
        application = try values.decode(Application.self, forKey: .application)
    }

 public func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: CodingKeys.self)
        try container.encode(application, forKey: .application)
    }
 }

I'm new to swift so sorry if I'm missing something very obvious. Im not able to fix this and I need some help in right direction. Thank you in advance.


Solution

  • How you address this strongly depends on the problem you're solving.

    If you want to store and load exactly these two keys in JSON, then Application should be a struct (as jawadAli notes).

    If you mean to store more information, but a given Component is tied to exactly one type of Application, then you want Component to be generic:

    public struct Component<App: Application & Codable> : Codable {
         let application : App
         ...
    }
    

    Note the addition of & Codable. If all things that conform to Application should be Codable, then you can make that a requirement of Application:

    public protocol Application: Codable {
         var name : String {get}
         var ownerName : String {get}
    }
    

    It is important to understand that this does not make Application conform to Codable. It means that in order to conform to Application, a type must also conform to Codable. It is never possible to decode an abstract type (i.e. a protocol).

    If you mean to store more information, but a given Component doesn't actually know what kind of Application it holds, then this is a more complicated problem (and often over-complicated and should be rethought; if you find you're using a lot of as? tests, then you should almost certainly redesign). If that's your problem, you should explain a bit more what problem you're solving, and we can discuss how to solve it. (It generally requires some kind of dynamic type registration system, and a JSON format that supports metadata about types. Or you can switch to NSCoder and not use JSON.)