web-dev-qa-db-ja.com

funcのタイプとしてプロトコル「エンコード可能」を使用できないのはなぜですか

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

ソリューション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()
16
SPatel

あなたの2つの例は異なります。

JSONEncoder()。encode() は、プロトコルEncodableに準拠する具象クラスを期待します。参照dataSource2は、具体的なクラスではなくプロトコルを保持します。

一方、logItemは入力としてプロトコルのみを受け取り、プロトコルに準拠する具象クラスは持ちません。これが例の違いであり、2番目のケースが機能し、1番目のケースが機能しない理由です。

現在の設定では、機能しません。具体的なクラスをJSONEncoderに渡す必要があります。

1
J. Doe

この問題を解決するには、いくつかの方法があります。

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)
1
So Over It

限り TestClass2Encodableです。次のコードを使用できます。 encodeは何をエンコードするかを知っている必要があります。それを行うには、クラスプロパティを参照します。 Encodable自体にはプロパティは含まれていません。

JSONEncoder().encode(dataSource2 as! TestClass2)
0
Sedo