如何使用 ObjectMapper 映射不同类型?

How to map different type using ObjectMapper?

我正在使用 ObjectMapper 将我的 JSON 映射到 Swift 对象。

我有以下 Swift 对象:

class User: Mappable {

    var name: String?
    var val: Int?

    required init?(map: Map) { }

    func mapping(map: Map) {
        name <- map["name"]
        val  <- map["userId"]
    }
}

我有这个 JSON 结构:

{
   "name": "first",
   "userId": "1" // here is `String` type.
},
{
   "name": "second",
   "userId": 1 // here is `Int` type.
}

映射 JSON 后, UseruserId 其中 name"first" 为空。

如何将 Int/String 映射到 Int

你应该提高你的API。但是,如果您不能这样做,请尝试此代码:

class User: Mappable {

    var name: String?
    var val: Int?

    required init?(map: Map) { }

    func mapping(map: Map) {
        name <- map["name"]

        // 1: Get the value of JSON and store it in a variable of type Any?
        var userIdData: Any?
        userIdData <- map["userId"]

        // 2: Check the value type of the value and convert to Int type
        if userIdData is Int {
            val = (userIdData as! Int) 
        } else if userIdData is String {
            val = Int(userIdData as! String) 
        }
    }
}

你可以参考这个文档:Type Casting

如果你的API是这样的-那是非常糟糕的API。你可以做的是有两个变量而不是一个:

class User: Mappable {

    var name: String?
    var valInt: Int?
    var valString: String?

    required init?(map: Map) { }

    func mapping(map: Map) {
        name <- map["name"]
        valInt  <- map["val"]
        valString <- map["val"]
    }
}

您甚至可以添加能为您带来价值的功能,例如:

// bellow func mapping(map: Map){
func getUserId() -> String {
     if(self.valInt != nil) {
         return "\(valInt!)"
     }
     else {
         return valString!
     }
}

或者,使用 if let:

func getUserId() -> String {
     if let userId  = self.valInt {
         return "\(userId)"
     }
     if let userId = valString {
         return userId
     }
     return ""
}

或者使用可选项,以便稍后您可以使用 if let userId = object.getUserId()

func getUserId() -> String? {
     if(self.valInt != nil) {
         return String(valInt)
     }
     else {
         return valString
     }
}

看了ObjectMapper的代码后,我发现了一个更简单的解决问题的方法,就是自定义transform。

public class IntTransform: TransformType {

    public typealias Object = Int
    public typealias JSON = Any?

    public init() {}

    public func transformFromJSON(_ value: Any?) -> Int? {

        var result: Int?

        guard let json = value else {
            return result
        }

        if json is Int {
            result = (json as! Int)
        }
        if json is String {
            result = Int(json as! String)
        }

        return result
    }

    public func transformToJSON(_ value: Int?) -> Any?? {

        guard let object = value else {
            return nil
        }

        return String(object)
    }
}

然后,对 mapping 函数使用自定义转换。

class User: Mappable {

    var name: String?
    var userId: Int?

    required init?(map: Map) { }

    func mapping(map: Map) {
        name   <- map["name"]
        userId <- (map["userId"], IntTransform()) // here use the custom transform.
    }
}

希望对遇到同样问题的人有所帮助。 :)