web-dev-qa-db-ja.com

JSONEncoderを使用して、型としてCodableを使用して変数をエンコードする

JSONとplistのエンコードとデコードの両方を機能させることができましたが、特定のオブジェクトでエンコード/デコード関数を直接呼び出すだけでした。

例えば:

struct Test: Codable {
    var someString: String?
}

let testItem = Test()
testItem.someString = "abc"

let result = try JSONEncoder().encode(testItem)

これは問題なく機能します。

ただし、Codableプロトコル準拠のみをタイプとして取り込んでそのオブジェクトを保存する関数を取得しようとしています。

func saveObject(_ object: Encodable, at location: String) {
    // Some code

    let data = try JSONEncoder().encode(object)

    // Some more code
}

これにより、次のエラーが発生します。

タイプ「(エンコード可能)」の引数リストで「エンコード」を呼び出すことはできません

エンコード関数の定義を見ると、Encodableが私が知らない奇妙な型でない限り、Valueを受け入れることができるように思えます。

open func encode<Value>(_ value: Value) throws -> Data where Value : Encodable
34
Denis Balko

Encodableに制限されたジェネリック型を使用する

func saveObject<T : Encodable>(_ object: T, at location: String) {
    //Some code

    let data = try JSONEncoder().encode(object)

    //Some more code
}
62
vadian

Encodableプロトコルを必要なすべてのインスタンスメソッドで拡張するのとは異なるアプローチを使用します。それを拡張すると、カスタムエンコーダーを渡し、すべてのメソッドにデフォルトエンコーダーを提供するために、メソッドにパラメーターを追加できます。

extension Encodable {
    func data(using encoder: JSONEncoder = JSONEncoder()) throws -> Data {
        return try encoder.encode(self)
    }
    func string(using encoder: JSONEncoder = JSONEncoder()) throws -> String {
        return try String(data: encoder.encode(self), encoding: .utf8)!
    }
}

使用法

let message = ["key":["a","b","c"]]

let jsonData = try! message.data() // 21 bytes [123, 34, 107, 101, 121, 34, 58, 91, 34, 97, 34, 44, 34, 98, 34, 44, 34, 99, 34, 93, 125]
let jsonString = try! message.string()  // "{"key":["a","b","c"]}"

デフォルトのエンコーダーで日付を渡す場合の例。使用されるdateEncodingStrategyはデフォルト(timeIntervalSinceReferenceDateを表すDouble)であることに注意してください。

let message = ["createdAt": Date()]

let jsonData = try! message.data() // 33 bytes -> [123, 34, 99, 114, 101, 97, 116, 101, 97, 100, 65, 116, 34, 58, 53, 55, 49, 54, 49, 55, 56, 52, 49, 46, 52, 53, 48, 55, 52, 52, 48, 51, 125]
let jsonString = try! message.string()  // {"createdAt":571617841.45074403}"

これで、カスタムエンコーダーをメソッドに渡して、人間が読める形式で日付をフォーマットできます。

let message = ["createdAt": Date()]
let encoder = JSONEncoder()
encoder.dateEncodingStrategy = .iso8601
let jsonString = try! message.string(using: encoder)  // "{"createdAt":"2019-02-11T22:48:19Z"}"

カスタムメッセージ構造を使用するようになりました

struct Message: Codable {
    let id: Int
    let createdAt: Date
    let sender, title, body: String
}

extension Encodable {
    func sendDataToServer(using encoder: JSONEncoder = JSONEncoder()) throws {
        print(self, terminator: "\n\n")
        // Don't handle the error here. Propagate the error.
        let data = try self.data(using: encoder)
        print(String(data: data, encoding: .utf8)!)
        // following the code to upload the data to the server
        print("Message was successfully sent")
    }
}

let message = Message(id: 1, createdAt: Date(), sender: "[email protected]", title: "Lorem Ipsum", body: """
Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.
""")

let iso8601 = JSONEncoder()
iso8601.dateEncodingStrategy = .iso8601
iso8601.outputFormatting = .prettyPrinted
do {
    try message.sendDataToServer(using: iso8601)
} catch {
    // handle all errors
    print(error)
}

これは印刷されます

Message(id: 1, createdAt: 2019-02-11 23:57:31 +0000, sender: "[email protected]", title: "Lorem Ipsum", body: "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry\'s standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.")

{
  "body" : "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.",
  "id" : 1,
  "sender" : "[email protected]",
  "title" : "Lorem Ipsum",
  "createdAt" : "2019-02-11T23:57:31Z"
}
now just add the code to send the json data to the server
1
Leo Dabus

ジェネリック型Encodableでジェネリック関数を使用する必要があります

できません

func toData(object: Encodable) throws -> Data {
  let encoder = JSONEncoder()
  return try encoder.encode(object) // Cannot invoke 'encode' with an argument list of type '(Encodable)'
}

あなたはできる

func toData<T: Encodable>(object: T) throws -> Data {
  let encoder = JSONEncoder()
  return try encoder.encode(object)
}
0
onmyway133