0

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.

Jawad Ali
  • 13,556
  • 3
  • 32
  • 49
Jaffer Sheriff
  • 1,444
  • 13
  • 33

2 Answers2

3

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.)

Rob Napier
  • 286,113
  • 34
  • 456
  • 610
  • 1
    Thanks man. I really appreciate your detailed answer. I fixed my issue by creating an intermediary struct and saving it in disk. – Jaffer Sheriff May 08 '20 at 09:43
2

Use Struct that is confirming to codable instead of protocol will solve the issue

public struct Application : Codable {
     var name : String
     var ownerName : String
}
Jawad Ali
  • 13,556
  • 3
  • 32
  • 49