在 Swift 中,我们经常需要处理 JSON、plist 以及各种形式的 [String: Any]
。Outlaw
提供各种方法,以一种富有表现力且类型安全的方式来处理这些数据。Outlaw
将利用面向协议编程™的力量,帮助你编写声明式、高性能、错误处理完备的代码。
使用 Outlaw 从 [String: Any]
中提取值非常简单,就像这样:
let name: String = try json.value(for: "name")
let url: URL = try json.value(for: "user.website") // extract from nested objects!
通常,我们希望获取一个可提取的对象(例如 [String: Any]
),并将其反序列化为我们的本地模型。例如,我们可能希望获取一些 JSON 并使用它来初始化我们的本地模型。
struct User: Deserializable {
var id: Int
var name: String
var email: String
init(object: Extractable) throws {
id = try object.value(for: "id")
name = try object.value(for: "name")
email = try object.value(for: "email")
}
}
现在,仅通过提供一个简单的初始化器,你就可以直接从 [String: Any]
中提取你的模型!
let users: [User] = try json.value(for: "users")
这太简单了!感谢面向协议编程™!
我们已经了解了如何从 [String: Any]
转换为我们的本地模型,但反过来呢?
extension User: Serializable {
func serialized() -> [String: Any] {
return [
"id": "id",
"name" : name,
"email": email
]
}
}
现在,你可能会想“我不能使用反射来自动完成这个吗?”你可以。如果你喜欢这样做,有一些其他很棒的框架供你使用。但 Outlaw 认为使用反射可能会导致问题。Outlaw 坚信所见即所得™,并且你可以轻松适应蛇形命名、驼峰命名,或者你的后端开发人员喜欢的任何命名风格的 API。Outlaw 代码是显式的、声明式的。不要只听 Outlaw 的一面之词——请阅读官方 Swift 博客中 这篇好文章的结尾。
你是不关心错误的人吗?使用可选数据类型。
let users: [User]? = json.value(for: "users")
否则,将你的代码包装在 do-catch
块中,以便在出现问题时获取所有详细信息。
do {
let users: [User] = try json.value(for: "users")
}
catch {
print(error)
}
开箱即用,Outlaw
支持提取原生 Swift 类型,例如 String
、Int
等,以及 URL
、Date
和任何符合 Deserializable
协议的类型,以及上述所有类型的数组或字典。
但是,Outlaw 不会让你孤立无援!添加你自己的 Outlaw 值类型就像用 Value
扩展你的类型一样简单。
extension CGPoint: Value {
public static func value(from object: Any) throws -> CGPoint {
guard let properties = object as? [String: CGFloat] else {
throw OutlawError.typeMismatch(expected: [String: CGFloat].self, actual: type(of: object))
}
let x: CGFloat = properties["x"] ?? 0
let y: CGFloat = properties["y"] ?? 0
return CGPoint(x: x, y: y)
}
}
通过简单地实现 value(from:)
,Outlaw 允许你立即这样做:
let point: CGPoint = try json.value(for: "point")
面向协议编程™ 再次发力!
不喜欢 Outlaw
实现的默认值提取方式吗?有不同的日期格式?没问题!提取值时,你只需要一个转换函数。
let formatter = DateFormatter()
formatter.timeZone = TimeZone(abbreviation: "GMT")
formatter.dateFormat = "MM/dd/yyyy"
let date: Date? = json.value(for: "date", with: { (dateString: String) -> Date? in
return formatter.date(from: dateString)
})
我们还可以利用 swift 的强大功能,将上面的代码缩短为:
let date: Date? = json.value(for: "date", with: formatter.date)
Outlaw 基于与 Marshal 相同的底层代码,并且具有相同的性能。你总是应该对基准测试持保留态度,但无论如何,请看看 这些基准测试。不幸的是,JSONShootout 项目的构建方式使得无法添加 Outlaw,因为与 Marshal 存在模糊的方法冲突。
Outlaw
由 Marshal 的主要贡献者之一创建。但是,Marshal
被设计为一个精简的框架,需要扩展才能获得额外的功能。Outlaw
被设计为一个功能更丰富的框架,可以开箱即用地处理更多的数据提取场景。