Swift 通用可序列化协议
Swift generic Serializable protocol
我注意到我有很多 getting/sending JSON 到我的应用程序 API 的重复代码,但唯一不同的是实体是什么 (de)序列化。所以我想出了以下设计(为简洁起见,仅使用 GET 方法):
HTTPClient.swift
func getEntityJSON<T: JSONSerializable>(
type: T.Type,
url: String,
completionHandler: @escaping (_ result: T?,
_ headers: [String: String]?,
_ statusCode: Int?,
_ error: Error?) -> Void) {
HttpClient.sharedInstance().getJSON(url, completionHandler: { (jsonData, headers, statusCode, error) in
if let error = error {
completionHandler(nil, headers, statusCode, error)
} else {
if let entityData = jsonData {
completionHandler(T.fromJSON(data: entityData), headers, statusCode, nil)
}
}
})
}
打算这样使用它:
HTTPClient.sharedInstance().getEntity(type: Translation, url: url) { (translation, _, _, _) in
// do stuff with Translation instance
}
这里是 JSONSerializable
协议:
import Foundation
import SwiftyJSON
protocol Serializable: Codable {
static func deserialize<T: Codable>(data: Data) -> T?
func serialize() -> Data?
}
extension Serializable {
static func deserialize<T: Decodable>(data: Data) -> T? {
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
decoder.dateDecodingStrategy = .formatted(DateFormatter.iso8601Full)
return try? decoder.decode(T.self, from: data)
}
func serialize() -> Data? {
let encoder = JSONEncoder()
encoder.keyEncodingStrategy = .convertToSnakeCase
encoder.dateEncodingStrategy = .formatted(DateFormatter.iso8601Full)
return try? encoder.encode(self)
}
}
protocol JSONSerializable: Serializable {
func toJSON() -> JSON?
static func fromJSON<T>(data: JSON) -> T?
}
extension JSONSerializable {
func toJSON() -> JSON? {
if let data = self.serialize() {
return try? JSON(data: data)
} else {
return nil
}
}
}
这让我可以定义这样的结构:
Translation.swift
struct Translation: Hashable, Identifiable, JSONSerializable {
var id: UUID
...
static func fromJSON(data: JSON) -> Translation? {
我将获得 serialize, deserialize, toJSON
功能。但是编译器抱怨 Translation
不符合 JSONSerializable
,因为缺少:
static func fromJSON<T>(data: JSON) -> T?
。我以为我可以用具体类型实现该功能,在这种情况下为 Translation
。
我希望既能做到 Translations.fromJSON(data: data)
又能做到 T.fromJSON(data: data)
。我怎样才能做到这一点?
泛型 (<T>
) 意味着您的方法可以使用 调用者(不是被调用者,不是实施者,也不是其他任何人)指定的任何类型。在fromJSON
的情况下,显然不是这样。 fromJSON
的任何具体实现仅适用于 T
作为封闭类型,因此 fromJSON
不适合通用。
当方法“仅适用于 T
作为封闭类型”时,它是 Self
类型的用例:
protocol JSONSerializable: Serializable {
func toJSON() -> JSON?
static func fromJSON(data: JSON) -> Self?
}
这样,您的 Translation
实现将符合协议。
同样,deserialise
也应该声明为:
static func deserialize(data: Data) -> Self?
如果你真的想要一个可以将 JSON
转换为调用者想要的任何类型的 JSONSerialisable
,那么它就不是 JSONSerialisable
,而是 JSONSerialiser
,在这种情况下从 Codable
继承没有多大意义。
好的,我最终实现了 JSONSerializer
,因为我无法让它用于要(反)序列化的项目集合。这是它目前的样子:
import Foundation
import SwiftyJSON
protocol JSONSerializable {
static func fromJSON(data: JSON) -> Self?
}
class JSONSerializer {
static func deserialize<T: Decodable>(_ type: T.Type, data: Data) -> T? {
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
decoder.dateDecodingStrategy = .formatted(DateFormatter.iso8601Full)
return try? decoder.decode(type, from: data)
}
static func serialize<T: Encodable>(_ object: T) -> Data? {
let encoder = JSONEncoder()
encoder.keyEncodingStrategy = .convertToSnakeCase
encoder.dateEncodingStrategy = .formatted(DateFormatter.iso8601Full)
return try? encoder.encode(object)
}
static func fromJSON<T: JSONSerializable>(type: T.Type, data: JSON) -> T? {
T.fromJSON(data: data)
}
static func toJSON<T: Encodable>(_ object: T) -> JSON? {
if let data = Self.serialize(object) {
return try? JSON(data: data)
} else {
return nil
}
}
}
稍后我会研究 fromJSON
函数,看看我是否可以完全摆脱 JSONSerializable
并在 JSONSerializer
中实现它,如下所示:
static func fromJSON<T: Decodable>(type: T.Type, data: JSON) -> T? {
if let jsonData = try? data.rawData() {
return Self.deserialize(type, data: jsonData)
}
return nil
}
我注意到我有很多 getting/sending JSON 到我的应用程序 API 的重复代码,但唯一不同的是实体是什么 (de)序列化。所以我想出了以下设计(为简洁起见,仅使用 GET 方法):
HTTPClient.swift
func getEntityJSON<T: JSONSerializable>(
type: T.Type,
url: String,
completionHandler: @escaping (_ result: T?,
_ headers: [String: String]?,
_ statusCode: Int?,
_ error: Error?) -> Void) {
HttpClient.sharedInstance().getJSON(url, completionHandler: { (jsonData, headers, statusCode, error) in
if let error = error {
completionHandler(nil, headers, statusCode, error)
} else {
if let entityData = jsonData {
completionHandler(T.fromJSON(data: entityData), headers, statusCode, nil)
}
}
})
}
打算这样使用它:
HTTPClient.sharedInstance().getEntity(type: Translation, url: url) { (translation, _, _, _) in
// do stuff with Translation instance
}
这里是 JSONSerializable
协议:
import Foundation
import SwiftyJSON
protocol Serializable: Codable {
static func deserialize<T: Codable>(data: Data) -> T?
func serialize() -> Data?
}
extension Serializable {
static func deserialize<T: Decodable>(data: Data) -> T? {
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
decoder.dateDecodingStrategy = .formatted(DateFormatter.iso8601Full)
return try? decoder.decode(T.self, from: data)
}
func serialize() -> Data? {
let encoder = JSONEncoder()
encoder.keyEncodingStrategy = .convertToSnakeCase
encoder.dateEncodingStrategy = .formatted(DateFormatter.iso8601Full)
return try? encoder.encode(self)
}
}
protocol JSONSerializable: Serializable {
func toJSON() -> JSON?
static func fromJSON<T>(data: JSON) -> T?
}
extension JSONSerializable {
func toJSON() -> JSON? {
if let data = self.serialize() {
return try? JSON(data: data)
} else {
return nil
}
}
}
这让我可以定义这样的结构:
Translation.swift
struct Translation: Hashable, Identifiable, JSONSerializable {
var id: UUID
...
static func fromJSON(data: JSON) -> Translation? {
我将获得 serialize, deserialize, toJSON
功能。但是编译器抱怨 Translation
不符合 JSONSerializable
,因为缺少:
static func fromJSON<T>(data: JSON) -> T?
。我以为我可以用具体类型实现该功能,在这种情况下为 Translation
。
我希望既能做到 Translations.fromJSON(data: data)
又能做到 T.fromJSON(data: data)
。我怎样才能做到这一点?
泛型 (<T>
) 意味着您的方法可以使用 调用者(不是被调用者,不是实施者,也不是其他任何人)指定的任何类型。在fromJSON
的情况下,显然不是这样。 fromJSON
的任何具体实现仅适用于 T
作为封闭类型,因此 fromJSON
不适合通用。
当方法“仅适用于 T
作为封闭类型”时,它是 Self
类型的用例:
protocol JSONSerializable: Serializable {
func toJSON() -> JSON?
static func fromJSON(data: JSON) -> Self?
}
这样,您的 Translation
实现将符合协议。
同样,deserialise
也应该声明为:
static func deserialize(data: Data) -> Self?
如果你真的想要一个可以将 JSON
转换为调用者想要的任何类型的 JSONSerialisable
,那么它就不是 JSONSerialisable
,而是 JSONSerialiser
,在这种情况下从 Codable
继承没有多大意义。
好的,我最终实现了 JSONSerializer
,因为我无法让它用于要(反)序列化的项目集合。这是它目前的样子:
import Foundation
import SwiftyJSON
protocol JSONSerializable {
static func fromJSON(data: JSON) -> Self?
}
class JSONSerializer {
static func deserialize<T: Decodable>(_ type: T.Type, data: Data) -> T? {
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
decoder.dateDecodingStrategy = .formatted(DateFormatter.iso8601Full)
return try? decoder.decode(type, from: data)
}
static func serialize<T: Encodable>(_ object: T) -> Data? {
let encoder = JSONEncoder()
encoder.keyEncodingStrategy = .convertToSnakeCase
encoder.dateEncodingStrategy = .formatted(DateFormatter.iso8601Full)
return try? encoder.encode(object)
}
static func fromJSON<T: JSONSerializable>(type: T.Type, data: JSON) -> T? {
T.fromJSON(data: data)
}
static func toJSON<T: Encodable>(_ object: T) -> JSON? {
if let data = Self.serialize(object) {
return try? JSON(data: data)
} else {
return nil
}
}
}
稍后我会研究 fromJSON
函数,看看我是否可以完全摆脱 JSONSerializable
并在 JSONSerializer
中实现它,如下所示:
static func fromJSON<T: Decodable>(type: T.Type, data: JSON) -> T? {
if let jsonData = try? data.rawData() {
return Self.deserialize(type, data: jsonData)
}
return nil
}