测试测试 | ✓ |
语言语言 | SwiftSwift |
许可证 | MIT |
发布最新发布 | 2017 年 9 月 |
SwiftSwift 版本 | 3.0 |
SPM支持 SPM | ✓ |
由 David Ohayon,Johannes Lund 维护。
简单、严格,并且强大的对象映射(通过 Swift 2 的错误处理实现)。深受 Argo 启发,但没有亿万级功能操作符。
struct Repository {
let name: String
let description: String
let stargazersCount: Int
let language: String?
let sometimesMissingKey: String?
let owner: User // Struct conforming to Decodable
let defaultBranch: Branch // Struct NOT conforming to Decodable
var fullName: String { return "\(owner.login)/\(name)" }
}
extension Repository: Decodable {
static func decode(j: Any) throws -> Repository {
return try Repository(
name: j => "nested" => "name",
description: j => "description",
stargazersCount: j => "stargazers_count",
language: j => "language",
sometimesMissingKey: j =>? "sometimesMissingKey",
owner: j => "owner",
defaultBranch: Branch(name: j => "default_branch")
)
}
}
do {
let json = try NSJSONSerialization.JSONObjectWithData(data, options: [])
let repo = try [Repository].decode(json)
} catch {
print(error)
}
public protocol Decodable {
static func decode(json: AnyObject) throws -> Self
}
public func parse<T>(json: AnyObject, path: [String], decode: (AnyObject throws -> T)) throws -> T
太多的生成的重载,都调用了 parse
函数,可以在 Overloads.swift 中找到。返回类型包括 T?
,[T?]
,[T?]?
,AnyObject
和 [String: T]?
。当 Swift 支持条件协议遵循时,这一点将不再是必要的,并且自动解码无限嵌套泛型类型(如 [[[[[[[[[A???]]: B]]]?]]?]]
)将工作。
一个重载可能看起来像这样
public func => <T: Decodable>(json: AnyObject, keyPath: KeyPath) throws -> T
键路径可以由字符串字面量和数组字面量以及显式初始化器创建。它们也可以使用 =>
和 =>?
操作符连接。=>?
是另一个操作符,表示如果右侧缺乏键则应返回 nil
。
=>
和 =>?
操作符时,=>
的严格性仍然得到尊重。=>?
)需要一个可选返回类型let a: KeyPath = "a"
let b: KeyPath = ["a", "b"]
let c: KeyPath = "a" => "b" => "c"
let string: String? = json =>? "key1" => "key2" => "key3"`
^^^^ allowed to be missing
错误将在解码过程中被捕捉并重新抛出,以回传元数据,例如失败解码的 JSON 对象,它的键路径和根 JSON 对象。
有关更多的信息请查看 DecodingError.swift
public enum DecodingError: ErrorProtocol, Equatable {
/// Thrown when optional casting from `AnyObject` fails.
///
/// This can happen both when trying to access a key on a object
/// that isn't a `NSDictionary`, and failing to cast a `Castable`
/// primitive.
case typeMismatch(expected: Any.Type, actual: Any.Type, Metadata)
/// Thrown when a given, required, key was not found in a dictionary.
case missingKey(String, Metadata)
/// Thrown from the `RawRepresentable` extension when
/// `init(rawValue:)` returned `nil`.
case rawRepresentableInitializationError(rawValue: Any, Metadata)
/// When an error is thrown that isn't `DecodingError`, it
/// will be wrapped in `DecodingError.other` in order to also provide
/// metadata about where the error was thrown.
case other(ErrorProtocol, Metadata)
}
let dict: NSDictionary = ["object": ["repo": ["owner": ["id" : 1, "login": "anviking"]]]]
do {
let username: String = try dict => "object" => "repo" => "owner" => "name"
} catch let error {
print(error)
}
//
// MissingKeyError at object.repo.owner: name in {
// id = 1;
// login = anviking;
// }
如 j => "key"
之类的表达式将直接抛出错误,并可以使用 catch
语句创建最复杂的错误处理行为。这也意味着可以使用 try?
返回 nil,而不是抛出错误。
为了方便,有一个操作符 =>?
,它只在对缺失的键返回 nil。这种 API 用这种方式指示 null
,以帮助处理不同的响应格式。
重载 | 空值行为 | 缺失键的行为 | 类型不匹配的行为 | 子对象中的错误 |
---|---|---|---|---|
=> -> T | 抛出异常 | 抛出异常 | 抛出异常 | 未捕获(抛出异常) |
=> -> T? | nil | 抛出异常 | 抛出异常 | 未捕获(抛出异常) |
=>? -> T? | nil | nil | 抛出异常 | 未捕获(抛出异常) |
try? => -> T | nil | nil | nil | 捕获(nil) |
类型如 Int
、Double
、String
、Bool
、Date
(ISO8601)、NSArray
和 NSDictionary
,它们必须遵守以下声明以符合 DynamicDecodable
public protocol DynamicDecodable {
associatedtype DecodedType
static var decoder: (Any) throws -> DecodedType {get set}
}
这样允许 Decodable 在需要时覆盖默认的解码闭包。
// Lets extend Bool.decoder so that it accepts certain strings:
Bool.decoder = { json in
switch json {
case let str as String where str == "true":
return true
case let str as String where str == "false":
return false
default:
return try cast(json)
}
}
注意,当扩展新类型以符合 Decodable
时,实际上没有理由遵守 DynamicDecodable
,因为您已经控制了实现。另外,请注意 decoder
属性是作为“一次性设置”的。如果您需要在不同的场合有不同的行为,请创建自定义的解码函数。
默认的 Date.decoder
使用 ISO8601 日期格式化程序。如果您不想创建自己的解码闭包,有一个辅助程序
Date.decoder = Date.decoder(using: formatter)
Decodable
不够的时候不要害怕不遵守 Decodable
。
let array = try NSArray.decode(json => "list").map {
try Contribution(json: $0, repository: repo)
}
Decodable
。只需确保对 self 调用一个 required
初始化器(例如 self.init
)并返回 Self
,或者将您的类设置为 final
。( 这可能是一个问题)Decodable
-协议和 =>
-运算符而让您不得不在所有地方使用它们。Swift 版本 | 兼容标签或分支 |
---|---|
Swift 3.0 | v0.5 |
Swift 2.3 | v0.4.4 |
Swift 2.2 | v0.4.3 |