Snake 2.0.3

Snake 2.0.3

测试已测试
语言语言 SwiftSwift
许可证 MIT
发布上次发布2021年10月
SPM支持SPM

Nodes Agency维护。



Snake 2.0.3

Serpent

CircleCI Codecov codebeat badge Carthage Compatible CocoaPods
Plaforms GitHub license

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

它设计为与我们的辅助应用程序一起使用,即ModelBoilerModel Boiler,使得模型创建变得轻松。

Snake使用协议扩展和静态类型实现。

📑目录

🐍为什么选择Snake?

有许多其他编码和解码框架可供选择。为什么您应该使用Snake?

  • 性能。Snake速度快,比类似框架快四倍。
  • 特性。Snake可以解析您抛给它的任何内容。嵌套对象、枚举、URL、UIColor 等!
  • ModelBoilerModel Boiler。此类框架都需要编写繁琐的模板代码,需要花费大量时间。《a href="https://github.com/nodes-ios/ModelBoiler">ModelBoilerModel Boiler可以立即为您生成。
  • Alamofire集成。使用包含的Alamofire扩展,实现返回解析模型数据的API调用变得简单至极!
  • 可扩展性。添加对其他数据类型的解析变得容易。
  • 持久化。结合我们的缓存框架Cashier,Snake对象可以非常容易地持久化到磁盘。
  • Serpent Xcode 文件模板 使得在Xcode中创建模型文件更加容易。

📝要求

  • 支持iOS 8.0+ / macOS 10.10+ / tvOS 9.0+ / watchOS 2.0+
  • Swift 3.0+
    (旧版本中支持Swift 2.2 & Swift 2.3)

📦安装

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()

更复杂的示例

在这个示例中,我们有两个模型,学生和学校。

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,通过扩展Alamofire的Request构造,添加了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的类型)。返回将作为可序列化初始化器的输入对象。

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。如果您需要解析其他日期格式,可以在代码中添加此行(例如,在AppDelegate的didFinishLaunchingWithOptions:中)

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

自定义日期格式不会替代默认格式,它们仍然被支持。

👥致谢

❤️Nodes

📄许可证

Serpent遵从MIT许可证。有关更多信息,请参阅LICENSE文件。