Encodable
プロトコルに準拠したエンコードモデルでデータを取得しようとしています。しかし、以下のコードのようにfunc 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
しかし、別のデモではうまく機能しますが、なぜですか?
// MARK: - Demo1
protocol TestProtocol {
func test()
}
class TestClass1: NSObject, TestProtocol {
func test() {
print("1")
}
var x = 1
var y = 2
}
var dataSource1: TestProtocol?
dataSource1 = TestClass1()
func logItem(_ value: TestProtocol) {
value.test()
}
logItem(dataSource1!)
ソリューション1。
エンコード可能に拡張するこのコードを試してください
extension Encodable {
func toJSONData() -> Data? {
return try? JSONEncoder().encode(self)
}
}
ソリューション2
アップルが提供するプロトコルを拡張機能で汚染しないようにするには
protocol MyEncodable: Encodable {
func toJSONData() -> Data?
}
extension MyEncodable {
func toJSONData() -> Data?{
return try? JSONEncoder().encode(self)
}
}
使用
var dataSource2: Encodable?
dataSource2 = TestClass2()
let data = dataSource2?.toJSONData()
あなたの2つの例は異なります。
JSONEncoder()。encode() は、プロトコルEncodable
に準拠する具象クラスを期待します。参照dataSource2
は、具体的なクラスではなくプロトコルを保持します。
一方、logItem
は入力としてプロトコルのみを受け取り、プロトコルに準拠する具象クラスは持ちません。これが例の違いであり、2番目のケースが機能し、1番目のケースが機能しない理由です。
現在の設定では、機能しません。具体的なクラスをJSONEncoderに渡す必要があります。
この問題を解決するには、いくつかの方法があります。
Encodable
を拡張する@SPatelソリューションは、1つの可能性です。ただし、私は個人的に、アップルが提供するプロトコルを拡張機能で汚染しないようにしています。
行間を読んでいる場合、あなたが望んでいるように見えます任意の構成some otherstruct/classの関数/メソッドのEncodable
に準拠します。
あなたが達成しようとしている私thinkの例を見てみましょう:
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)
限り TestClass2
はEncodable
です。次のコードを使用できます。 encode
は何をエンコードするかを知っている必要があります。それを行うには、クラスプロパティを参照します。 Encodable
自体にはプロパティは含まれていません。
JSONEncoder().encode(dataSource2 as! TestClass2)