Why can not use protocol `Encodable` as a type in the func

Solution 1.

https://github.com/satishVekariya/SVCodable

Try this code, which extend encodable

extension Encodable {
    func toJSONData() -> Data? { try? JSONEncoder().encode(self) }
}

Solution 2.

To avoid polluting Apple-provided protocols with extensions

protocol MyEncodable: Encodable {
    func toJSONData() -> Data?
}

extension MyEncodable {
    func toJSONData() -> Data?{ try? JSONEncoder().encode(self) }
}

Use

var dataSource2: Encodable?
dataSource2 = TestClass2()
let data = dataSource2?.toJSONData()

There are a number of approaches to solving this problem.

@SPatel solution of extending Encodable is one possibility. However, I personally try to avoid polluting Apple-provided protocols with extensions.

If I am reading between the lines, it appears what you are wanting is to pass any construct that conforms to Encodable to a function/method in some other struct/class.

Let's take an example of what I think you are trying to achieve:

struct Transform {
    static func toJson(encodable: Encodable) throws -> Data {
        return try JSONEncoder().encode(encodable)
    }
}

However, Xcode will complain:

Protocol type 'Encodable' cannot conform to 'Encodable' because only concrete types can conform to protocols

A Swift-ier solution is to use a constrained generic on the function:

struct Transform {
    static func toJson<EncodableType: Encodable>(encodable: EncodableType) throws -> Data {
        return try JSONEncoder().encode(encodable)
    }
}

Now the compiler can infer the type that conforms to Encodable, and we can call the function as intended:

let dataSource = TestClass2()
let jsonData = try? Transform.toJson(encodable: dataSource)

You can't pass a protocol but you can use generics to require a class that conforms to one:

func printJSON<T: Encodable>(_ data: T) {
    if let json = try? JSONEncoder().encode(data) {
        if let str = String(data: json, encoding: .utf8) {
            print(str)
        }
    }
}

// Now this should work
var dataSource2 = TestClass2()
printJSON(dataSource2!)