使用 JSONEncoder 对类型为 Codable 的变量进行编码

Using JSONEncoder to encode a variable with Codable as type

我设法让 JSON 和 plist 编码和解码工作,但只能通过在特定对象上直接调用 encode/decode 函数。

例如:

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
}

这会导致以下错误:

Cannot invoke 'encode' with an argument list of type '(Encodable)'

查看编码函数的定义,似乎它应该能够接受 Encodable,除非 Value 是某种我不知道的奇怪类型。

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

使用限制为 Encodable

的通用类型
func saveObject<T : Encodable>(_ object: T, at location: String) {
    //Some code

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

    //Some more code
}

您需要使用具有泛型类型的泛型函数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)
}

我会使用不同的方法来使用您可能需要的所有实例方法扩展 Encodable 协议。对此进行扩展,您可以向您的方法添加一个参数以传递自定义编码器并为所有这些方法提供默认编码器:

extension DataProtocol {
    var string: String? { String(bytes: self, encoding: .utf8) }
}

extension Encodable {
    func data(using encoder: JSONEncoder = JSONEncoder()) throws -> Data { try encoder.encode(self) }
    func string(using encoder: JSONEncoder = JSONEncoder()) throws -> String { try data(using: encoder).string ?? "" }
}

用法

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(data.string!)
        // following the code to upload the data to the server
        print("Message was successfully sent")
    }
}

let message = Message(id: 1, createdAt: Date(), sender: "user@company.com", 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: "user@company.com", 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" : "user@company.com",
  "title" : "Lorem Ipsum",
  "createdAt" : "2019-02-11T23:57:31Z"
}
now just add the code to send the json data to the server