ObjectMapper 是一个用 Swift 编写的框架,它使您能够轻松地将 Model 对象(类和结构体)与 JSON 之间相互转换。
为了支持映射,类或结构体只需要实现 Mappable
协议。
public protocol Mappable {
init?(_ map: Map)
mutating func mapping(map: Map)
}
ObjectMapper 使用 <-
操作符来定义每个成员变量如何映射到和从 JSON。
class User: Mappable {
var username: String?
var age: Int?
var weight: Double!
var array: [AnyObject]?
var dictionary: [String : AnyObject] = [:]
var bestFriend: User? // Nested User object
var friends: [User]? // Array of Users
var birthday: NSDate?
required init?(_ map: Map){
}
// Mappable
func mapping(map: Map) {
username <- map["username"]
age <- map["age"]
weight <- map["weight"]
array <- map["arr"]
dictionary <- map["dict"]
bestFriend <- map["best_friend"]
friends <- map["friends"]
birthday <- (map["birthday"], DateTransform())
}
}
struct Temperature: Mappable {
var celcius: Double?
var fahrenheit: Double?
init?(_ map: Map){
}
mutating func mapping(map: Map) {
celcius <- map["celcius"]
fahrenheit <- map["fahrenheit"]
}
}
一旦您的类实现了 Mappable,Mapper 类将为您处理其他所有事情
将 JSON 字符串转换为模型对象
let user = Mapper<User>().map(JSONString)
将模型对象转换为 JSON 字符串
let JSONString = Mapper().toJSONString(user, prettyPrint: true)
ObjectMapper 可以映射以下类型组成的类
ObjectMapper 支持在键内使用点表示法来简化嵌套对象的映射。给定以下 JSON 字符串:
"distance" : {
"text" : "102 ft",
"value" : 31
}
您可以像以下这样访问嵌套对象:
func mapping(map: Map){
distance <- map["distance.value"]
}
您也可以将深度数组对象映射到您的平面属性中
func mapping(map: Map){
currentEmployerName <- map["employments.0.employer.name"]
}
如果您有一个包含 .
的键,您可以取消以上功能,如下所示
func mapping(map: Map){
identifier <- map["app.identifier", nested: false]
}
为了验证服务器响应,您可以在映射规则规范中放置必须参数。验证使用系统的 assert
函数,这不会影响您的发布性能。
func mapping(map: Map){
identifier <- map["employment.Carma", required: true]
}
在测试中,将以下代码放在您的 setUp
测试函数中,以验证必须字段:
MapRequiredField.assume = { (condition: Bool, message: String) in
XCTAssert(condition, message)
}
ObjectMapper 同样支持自定义转换,在映射过程中转换值。要使用转换,只需创建一个元组,包含 map["field_name"]
和右边的 <-
操作符上你选择的转换。
birthday <- (map["birthday"], DateTransform())
上面的转换将普通 JSON Int 值转换为 NSDate 当读取 JSON 时,并将 NSDate 转换为 Int 当将对象转换为 JSON 时。
您可以通过采用并实现 TransformType 协议中的方法轻松创建自己的自定义转换。
public protocol TransformType {
typealias Object
typealias JSON
func transformFromJSON(value: AnyObject?) -> Object?
func transformToJSON(value: Object?) -> JSON?
}
在许多情况下,您可以使用内置转换类 TransformOf
快速执行所需的转换。 TransformOf
用两种类型和两个闭包初始化。类型定义了转换输入和输出的类型,闭包执行实际的转换。
例如,如果您想将 JSON String 值转换为 Int,可以像下面这样使用 TransformOf
:
let transform = TransformOf<Int, String>(fromJSON: { (value: String?) -> Int? in
// transform value from String? to Int?
return value?.toInt()
}, toJSON: { (value: Int?) -> String? in
// transform value from Int? to String?
if let value = value {
return String(value)
}
return nil
})
id <- (map["id"], transform)
下面提供了上述转换的更紧凑版本。
id <- (map["id"], TransformOf<Int, String>(fromJSON: { $0?.toInt() }, toJSON: { $0.map { String($0) } }))
实现 Mappable 协议的类可以轻松地被继承。当继承 Mappable 类时,请遵循以下结构。
class Base: Mappable {
var base: String?
required init?(_ map: Map){
}
func mapping(map: Map) {
base <- map["base"]
}
}
class Subclass: Base {
var sub: String?
required init?(_ map: Map){
super.init(map)
}
override func mapping(map: Map) {
super.mapping(map)
sub <- map["sub"]
}
}
注意:这是一个实验性功能。不可变映射并不保证 ObjectMapper 的所有功能都有效。
如果您有一个其属性不可变(let
)的类或结构体,并希望使用 ObjectMapper 来映射它,可以使用以下方法。
在可失败初始化方法中,使用 map
对象上的 valueOrFail()
函数为您的属性分配值。一旦所有属性都已设置,检查 isValid
以确定所有属性映射是否成功。如果 isValid
返回 false,返回 nil
以指示初始化失败。
class Model: Mappable {
let name: String // Non-optional property
required init?(_ map: Map) {
name = map["name"].valueOrFail()
if !map.isValid {
return nil
}
}
func mapping(map: Map) {
}
}
if let model = Mapper<Model>().map(JSONString) {
// Now we have valid model.
} else {
// Something wrong...
}
如果您正在使用 Alamofire 进行网络请求,并希望将响应转换为 Swift 对象,可以使用 AlamofireObjectMapper。它是一个简单的 Alamofire 扩展,使用 ObjectMapper 自动将 JSON 响应数据映射到 Swift 对象。
ObjectMapper 和 Realm 可以一起使用。只需遵循以下类结构,您就能使用 ObjectMapper 生成您的 Realm 模型。
class Model: Object, Mappable {
dynamic var name = ""
required convenience init?(_ map: Map) {
self.init()
}
func mapping(map: Map) {
name <- map["name"]
}
}
Note: Generating a JSON string of a Realm Object using ObjectMappers' `toJSON` function only works within a Realm write transaction. This is caused because ObjectMapper uses the `inout` flag in its mapping functions (`<-`) which are used both for serializing and deserializing. Realm detects the flag and forces the `toJSON` function to be called within a write block even though the objects are not being modified.
欢迎贡献
在提交任何 Pull Request 之前,请确保您已运行包含测试并保证它们通过。如果您包括新功能,请为它编写测试用例。
ObjectMapper 使用 Nimble 来确保测试成功。它是通过 Carthage 包括的。在 ObjectMapper 根目录下运行以下命令以获取 Nimble 依赖并准备测试环境:
carthage checkout
从现在开始,您应该使用 ObjectMapper.xcworkspace 打开项目,而不是 ObjectMapper.xcodeproj。
ObjectMapper 可以通过将以下行添加到您的 Podfile 来使用 Cocoapods 0.36 (beta) (通过 CocoaPods 框架开发指南)添加到您的项目中:
pod 'ObjectMapper', '~> 0.19'
否则,ObjectMapper 可以作为子模块添加。
cd
进入顶级项目目录,并输入命令git submodule add https://github.com/Hearst-DD/ObjectMapper.git
ObjectMapper.xcodeproj
拖到你的app项目文件导航器中。ObjectMapper.framework
。+
按钮,选择“New Copy Files Phase”,并将新阶段重命名为“Copy Frameworks”,设置“Destination”为“Frameworks”,并添加ObjectMapper.framework
。