Serpent (之前称为 Serializable) 是一个框架,用于创建模型对象或结构体,可以轻松地从/向 JSON 进行序列化和反序列化。它易于扩展,并处理使用 REST API 时使用的所有常见数据类型,以及自定义对象的递归解析。专为与 Alamofire 一起使用而设计。
它被设计为与我们的辅助应用程序 Model Boiler 一起使用,使模型创建变得轻而易举。
Serpent 是使用协议扩展和静态类型实现的。
市面上有许多其他的编码和解码框架。为什么你应该使用 Serpent?
github "nodes-ios/Serpent" ~> 1.0
与较低 Swift 版本兼容的最新版本
Swift 2.3
github "nodes-ios/Serpent" == 0.13.2
Swift 2.2
github "nodes-ios/Serpent" == 0.11.2
注意: Serpent 之前称为 Serializable。
选择以下其中一种,将其添加到你的 Podfile
并运行 pod install
pod 'Serpent', '~> 1.0' # Just core
pod 'Serpent/Extensions', '~> 1.0' # Includes core and all extensions
pod 'Serpent/AlamofireExtension', '~> 1.0' # Includes core and Alamofire extension
pod 'Serpent/CashierExtension', '~> 1.0' # Includes core and Cashier extension
注意: CocoaPods 仅支持使用 Swift 3.0 及更高版本的 Serpent。
要将 Serpent 用作 Swift Package Manager 包,只需将以下内容添加到你的 Package.swift
文件中。
import PackageDescription
let package = Package(
name: "YourPackage",
dependencies: [
.Package(url: "https://github.com/nodes-ios/Serpent.git", majorVersion: 1)
]
)
我们强烈建议你使用我们的 Model Boiler 来协助生成符合 Serpent 所需的代码。有关安装和使用说明,请访问 Model Boiler GitHub 仓库。
Serpent 支持所有原始类型、enum
、URL
、Date
、UIColor
、其他 Serpent
模型以及上述所有类型的 Array
。你的变量声明可以具有默认值或为可选类型。
如果 Swift 能够正常推断原始类型,则原始类型不需要具有显式类型。 var name: String = ""
与 var name = ""
的效果相同。可选类型当然需要显式类型。
注意: 你创建的枚举必须符合
RawRepresentable
协议,这意味着它们必须具有显式类型。否则,解析器将不知道如何处理它接收的传入数据。
struct Foo {
var id = 0
var name = ""
var address: String?
}
注意: 类必须标记为
final
。
extension Foo: Serializable {
init(dictionary: NSDictionary?) {
id <== (self, dictionary, "id")
name <== (self, dictionary, "name")
address <== (self, dictionary, "address")
}
func encodableRepresentation() -> NSCoding {
let dict = NSMutableDictionary()
(dict, "id") <== id
(dict, "name") <== name
(dict, "address") <== address
return dict
}
}
注意: 你可以添加对
Serializable
的符合性,它是Encodable
和Decodable
的类型别名。
就是这样!如果你正在使用 Model Boiler,此扩展将为你生成,因此你无需为你拥有的每个模型都将其全部键入。
可以使用字典创建模型的新实例,例如从解析后的 JSON。
let dictionary = try JSONSerialization.jsonObject(with: someData, options: .allowFragments) as? NSDictionary
let newModel = Foo(dictionary: dictionary)
你可以通过调用 encodableRepresentation()
生成模型的字典版本
let encodedDictionary = newModel.encodableRepresentation()
在这个例子中,我们有两个模型,Student 和 School。
struct Student {
enum Gender: String {
case male = "male"
case female = "female"
case unspecified = "unspecified"
}
var name = ""
var age: Int = 0
var gender: Gender?
}
struct School {
enum Sport: Int {
case football
case basketball
case tennis
case swimming
}
var name = ""
var location = ""
var website: URL?
var students: [Student] = []
var sports: [Sport]?
}
你可以根据需要使其尽可能复杂,语法将始终保持不变。扩展将是
extension Student: Serializable {
init(dictionary: NSDictionary?) {
name <== (self, dictionary, "name")
age <== (self, dictionary, "age")
gender <== (self, dictionary, "gender")
}
func encodableRepresentation() -> NSCoding {
let dict = NSMutableDictionary()
(dict, "name") <== name
(dict, "age") <== age
(dict, "gender") <== gender
return dict
}
}
extension School: Serializable {
init(dictionary: NSDictionary?) {
name <== (self, dictionary, "name")
location <== (self, dictionary, "location")
website <== (self, dictionary, "website")
students <== (self, dictionary, "students")
sports <== (self, dictionary, "sports")
}
func encodableRepresentation() -> NSCoding {
let dict = NSMutableDictionary()
(dict, "name") <== name
(dict, "location") <== location
(dict, "website") <== website
(dict, "students") <== students
(dict, "sports") <== sports
return dict
}
}
同样, Model Boiler 会在一秒钟内为你生成所有这些代码!
Serpent 通过 Alamofire 的 Request
构造上的扩展,开箱即用地与 Alamofire 集成,这增加了函数 responseSerializable(completion:unwrapper)
该扩展使用 Alamofire 熟悉的 Response
类型来保存返回的数据,并使用其泛型关联类型来自动解析数据。
考虑一个端点返回与上面示例中的结构体匹配的单个 school
结构。要实现调用,只需在你的共享连接管理器或任何你喜欢放置它的地方添加一个函数
func requestSchool(completion: @escaping (DataResponse<School>) -> Void) {
request("http://somewhere.com/school/1", method: .get).responseSerializable(completion)
}
在使用方法中,你像这样使用它
requestSchool() { (response) in
switch response.result {
case .success(let school):
//Use your new school object!
case .failure(let error):
//Handle the error object, or check your Response for more detail
}
}
对于对象数组,使用相同的技术
static func requestStudents(completion: @escaping (DataResponse<[Student]>) -> Void) {
request("http://somewhere.com/school/1/students", method: .get).responseSerializable(completion)
}
一些 API 将其数据包装在容器中。为此使用 unwrapper
闭包。假设你的 /students
端点返回包装在 students
对象中的数据
{
"students" : [
{
"..." : "..."
},
{
"..." : "..."
}
]
}
unwrapper
闭包有 2 个输入参数:sourceDictionary
(JSON 响应字典)和 expectedType
(目标 Serpent 的类型)。返回将用作 Serializable 初始化器输入的对象。
static func requestStudents(completion: (DataResponse<[Student]>) -> Void) {
request("http://somewhere.com/school/1/students", method: .get).responseSerializable(completion, unwrapper: { $0.0["students"] })
}
如果你需要在每次调用中解包响应数据,你可以使用以下代码安装默认的解包器
Parser.defaultWrapper = { sourceDictionary, expectedType in
// You custom unwrapper here...
return sourceDictionary
}
expectedType
可用于基于类型名称使用反射动态确定键。这在处理分页数据时尤其有用。
请参阅此处,了解我们在 Nodes 的项目中如何使用它。
注意: responseSerializable
内部调用请求上的 validate().responseJSON()
,因此你不必这样做。
Serpent 可以从 JSON 中的日期字符串创建 Date
对象。默认情况下,Serpent 可以解析以下格式的日期字符串:yyyy-MM-dd'T'HH:mm:ssZZZZZ
、yyyy-MM-dd'T'HH:mm:ss
、yyyy-MM-dd
。如果你需要解析其他日期格式,你可以通过将此行添加到你的代码中来完成(例如,在 AppDelegate
的 didFinishLaunchingWithOptions:
中
Date.customDateFormats = ["yyyyMMddHHmm", "yyyyMMdd"] // add the custom date formats you need here
自定义日期格式不会替换默认格式,它们仍将受到支持。
用 ❤️ 在 Nodes 制作。
Serpent 在 MIT 许可证下可用。有关更多信息,请参阅 LICENSE 文件。