这个库已被弃用,代码仓库也已归档。

代码仍然在这里,你仍然可以克隆它,但是该库将不再收到任何更新或支持。

Serpent

CircleCI Codecov codebeat badge Carthage Compatible CocoaPods
Plaforms GitHub license

Serpent (之前称为 Serializable) 是一个框架,用于创建模型对象或结构体,可以轻松地从/向 JSON 进行序列化和反序列化。它易于扩展,并处理使用 REST API 时使用的所有常见数据类型,以及自定义对象的递归解析。专为与 Alamofire 一起使用而设计。

它被设计为与我们的辅助应用程序 ModelBoiler Model Boiler 一起使用,使模型创建变得轻而易举。

Serpent 是使用协议扩展和静态类型实现的。

📑 目录

🐍 为什么选择 Serpent?

市面上有许多其他的编码和解码框架。为什么你应该使用 Serpent?

📝 要求

📦 安装

Carthage

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

CocoaPods

选择以下其中一种,将其添加到你的 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。

Swift Package Manager

要将 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)
    ]
)

🔧 设置

我们强烈建议你使用我们的 ModelBoiler Model Boiler 来协助生成符合 Serpent 所需的代码。有关安装和使用说明,请访问 Model Boiler GitHub 仓库

💻 用法

入门

Serpent 支持所有原始类型、enumURLDateUIColor、其他 Serpent 模型以及上述所有类型的 Array。你的变量声明可以具有默认值或为可选类型。

如果 Swift 能够正常推断原始类型,则原始类型不需要具有显式类型。 var name: String = ""var name = "" 的效果相同。可选类型当然需要显式类型。

注意: 你创建的枚举必须符合 RawRepresentable 协议,这意味着它们必须具有显式类型。否则,解析器将不知道如何处理它接收的传入数据。

创建你的模型结构体或类

struct Foo {
	var id = 0
	var name = ""
	var address: String?
}

注意: 类必须标记为 final

EncodableDecodable 添加必需的方法

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 的符合性,它是 EncodableDecodable 的类型别名。

就是这样!如果你正在使用 ModelBoiler Model Boiler,此扩展将为你生成,因此你无需为你拥有的每个模型都将其全部键入。

使用 Serpent 模型

可以使用字典创建模型的新实例,例如从解析后的 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
	}
}

同样,ModelBoiler Model Boiler 会在一秒钟内为你生成所有这些代码!

与 Alamofire 一起使用

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:ssZZZZZyyyy-MM-dd'T'HH:mm:ssyyyy-MM-dd。如果你需要解析其他日期格式,你可以通过将此行添加到你的代码中来完成(例如,在 AppDelegatedidFinishLaunchingWithOptions:

Date.customDateFormats = ["yyyyMMddHHmm", "yyyyMMdd"]    // add the custom date formats you need here

自定义日期格式不会替换默认格式,它们仍将受到支持。

👥 鸣谢

用 ❤️ 在 Nodes 制作。

📄 许可证

Serpent 在 MIT 许可证下可用。有关更多信息,请参阅 LICENSE 文件。