为什么不能在功能中使用协议“ Encodable”作为类型

时间:2018-06-27 08:42:20

标签: swift protocols encodable

我正在尝试通过符合<Reference Include="MYASM" />协议的编码模型来获取数据。但是像下面的代码那样调用func Encodable失败了:

encode

但是在另一个演示中,效果很好,为什么?

// MARK: - Demo2

class TestClass2: NSObject, Encodable {
    var x = 1
    var y = 2
}


var dataSource2: Encodable?

dataSource2 = TestClass2()

// error: `Cannot invoke 'encode' with an argument list of type '(Encodable)'`
let _ = try JSONEncoder().encode(dataSource2!)
//func encode<T>(_ value: T) throws -> Data where T : Encodable

5 个答案:

答案 0 :(得分:9)

尝试使用此代码,该代码可扩展

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

使用

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

答案 1 :(得分:1)

您的2个示例不同。

JSONEncoder().encode()需要符合Procotol [globalString = GP:tx_powermail_pi1|field|konsilbereich = "Some phrase"] 的具体类别。引用Encodable具有协议,而不是具体的类。

另一方面,

dataSource2仅将协议作为输入,并且没有符合该协议的具体类。这是您的示例之间的区别,以及为什么第二种情况有效而第一种情况无效的原因。

在当前设置下,它将无法正常运行。您需要将具体的类传递给JSONEncoder。

答案 2 :(得分:1)

有很多方法可以解决此问题。

扩展Encodable

@SPatel解决方案是一种可能。但是,我个人试图避免污染带有扩展名的Apple提供的协议。

如果我在两行之间阅读,看来您想要的是将符合Encodable 任何构造 传递给以下函数/方法 其他 结构/类。

让我们举一个我想尝试实现的示例:

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

但是,Xcode会抱怨:

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

Swift-ier解决方案是在函数上使用受约束的泛型:

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

现在,编译器可以推断出符合Encodable的类型,并且我们可以按预期的方式调用该函数:

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

答案 3 :(得分:0)

只要TestClass2Encodable,就可以使用以下代码。 encode应该知道要编码什么。它指的是类属性。 Encodable本身不包含任何属性。

JSONEncoder().encode(dataSource2 as! TestClass2)

答案 4 :(得分:0)

您不能通过协议,但是可以使用泛型来要求符合一个协议的类:

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