How to define variable with type of Codable?

Viewed 5651

I want to create variable with type of Codable. And later to use it in the JSONEncoder class. I thought that code from below should work fine, but it gives me error:

Cannot invoke encode with an argument list of type (Codable).

How to declare codable variable that JSONEncoder will be taking without error?

struct Me: Codable {
    let id: Int
    let name: String
}

var codable: Codable? // It must be generic type, but not Me.

codable = Me(id: 1, name: "Kobra")

let data = try? JSONEncoder().encode(codable!)

Here is similar question how to pass Codable using function. But I am looking how to set Codable using variable (class variable).

3 Answers

I created the same scenario as yours:

struct Me: Codable
{
    let id: Int
    let name: String
}

struct You: Codable
{
    let id: Int
    let name: String
}

class ViewController: UIViewController
{
    override func viewDidLoad()
    {
        var codable: Codable?

        codable = Me(id: 1, name: "Kobra")
        let data1 = try? JSONEncoder().encode(codable)

        codable = You(id: 2, name: "Kobra")
        let data2 = try? JSONEncoder().encode(codable)
    }
}

The above code is not giving me any error. The only thing I changed is:

let data = try? JSONEncoder().encode(codable!)

I didn't unwrap codable and it is working fine.

I have used this way, maybe it helps on your case as well.

public protocol AbstractMessage: Codable {
  var id: Int { get } // you might add {set} as well
  var name: Int { get }
}

then created a method:

public func sendMessage<T>(message: T) where T: AbstractMessage {
  let json = try! String(data: JSONEncoder().encode(message), encoding: .utf8)!
  ...
}

Here I created a common protocol, and passed it as a generic type to my function.

Related