diff --git a/README.zh-cn.txt b/README.zh-cn.txt new file mode 100644 index 0000000..fde2234 --- /dev/null +++ b/README.zh-cn.txt @@ -0,0 +1,103 @@ +# JSONDecoder-Keypath + +[![CircleCI](https://img.shields.io/circleci/project/github/0111b/JSONDecoder-Keypath.svg)](https://circleci.com/gh/0111b/JSONDecoder-Keypath) [![Isues](https://img.shields.io/github/issues/0111b/JSONDecoder-Keypath.svg)](https://github.com/0111b/JSONDecoder-Keypath/issues) ![License](https://img.shields.io/badge/license-MIT-ff69b4.svg) ![Swift Package Manager](https://img.shields.io/badge/spm-supported-blue.svg) ![Cocoapods](https://img.shields.io/badge/cocoapods-supported-blue.svg) + +为 Foundation.JSONDecoder 添加嵌套键路径(key path)支持 + + + +- [设计初衷](#rationale) +- [用法](#usage) +- [实现原理](#under-the-hood) +- [安装](#installation) + - [Swift Package Manager](#swift-package-manager) + - [Cocoapods](#cocoapods) +- [总结](#conclusion) +- [计划与改进](#plans-and-improvements) + + + +### 设计初衷 + +在撰写本文时,我发现大多数流行的框架(主要是网络请求封装库)在处理键路径时采用了非常糟糕的方式。 + +假设我们有一个 `Decodable` (`Codable`) 对象,但在 API 响应中,该对象位于某个自定义路径下。大多数现有解决方案都提供了通过键路径提取对象的接口,并增加了 `Codable` 支持。但问题在于,在我见过的几乎所有案例中,其实现方式如下: +1. 使用 `JSONSerialization` 从 `Data` 中提取 `[String: Any]` +2. 在该字典中根据键路径进行查找 +3. 将找到的对象重新转换为 `Data` +4. 使用 `JSONDecoder` 解析该对象 + +显而易见,这种数据的来回转换造成了额外的资源浪费。此外,在处理大量数据时,这种做法非常不推荐。 + +本软件包消除了前 3 个步骤。 + +### 用法 + +假设你有一个 `Item` 模型 + +```Swift +struct Item: Codable { + ... +} +``` + +并且我们有如下 JSON: + +```JSON +{ + "foo" : +} +``` + +要解析它,你需要编写: + +```Swift +let jsonData: Data = ... +let item = try decoder.decode(Item.self, from: jsonData, keyPath: "foo") +``` + +同样支持嵌套键路径: + +```Swift +let item = try decoder.decode(Item.self, from: jsonData, keyPath: "foo.bar") +``` + +键路径分隔符可以自定义: + +```Swift +let item = try decoder.decode(Item.self, from: jsonData, keyPath: "foo/bar", keyPathSeparator: "/") +``` + +### 实现原理 + +本软件包为 `JSONDecoder` 添加了一个新方法: + +```Swift +func decode(_ type: T.Type, + from data: Data, + keyPath: String, + keyPathSeparator separator: String = ".") throws -> T where T : Decodable +``` + +在调用此方法时,`keypath` 被存储在 `JSONDecoder.userInfo` 中,随后调用标准的 `decode` 方法,并将私有类 `KeyPathWrapper` 作为类型参数。在 `KeyPathWrapper` 的构造函数中,从 `userInfo` 获取键路径数据并据此遍历解码器。之后,再对原始类型进行解码。 + +### 安装 + +#### Swift Package Manager + +将 `.Package(url: "https://github.com/0111b/JSONDecoder-Keypath.git")` 添加到你的 `Package.swift` 中。 + +#### Cocoapods + +```Ruby + pod 'JSONDecoder-Keypath' +``` + +### 总结 + +基本上,这是一个关于自定义对象编码的简单实现,我只花了几个小时就完成了。但它表明,我们必须思考如何利用提供的 API,而不能懒于研究其底层实现。 + +### 计划与改进 +- [ ] 扩展单元测试 +- [x] 添加 cocoapods spec +- [ ] 添加 Carthage 支持