2017-07-26 259 views
0

我使用ObjectMapper将我的JSON映射到Swift对象。如何使用ObjectMapper映射不同的类型?

我有以下夫特对象:

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,的UseruserIdname"first"为空后。

如何将Int/String映射到Int

+0

你不能这样做。你必须为UserId选择一个数据类型,不管它是Int还是String。 –

+0

''val“'在哪里? userId在JSON中的关键是“userId”,对吧? –

+0

@AnhTrungPham哦,这是我的错。是的,JSON中userId的关键是“userId”,我已经修复了它。谢谢。 –

回答

2

在阅读ObjectMapper的代码后,我发现了一个更简单的方法来解决这个问题,它是自定义转换。

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. 
    } 
} 

希望它可以帮助其他人有同样的问题。 :)

+0

哦,那很好。然而,为了更安全起见,在'transformFromJSON(_ value:Any?) - > Int?'函数中,我认为你应该将这行'result = Int(json as!String)!'改为result = Int as!String)?? 0'。这是因为如果'value' ='“ABC123”'你会得到一个致命的运行时错误。 –

+0

而且,它看起来像'transformFromJSON'函数永远不会返回'nil'。因此,考虑将'User'类中的'userId'变量更新为'Int'类型而不是'Int?'或者更新'transformFromJSON'函数返回'nil'而不是默认值'0'。 –

+0

还有一件事。你应该接受你的答案,这是一个很好的解决方案。 –

0

你应该改进你的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

+0

这是一个很好的解决我的问题,谢谢。 –

+0

乐意帮忙! :) –

1

如果你的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! 
    } 
} 

或者,使用如果让:

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 
    } 
} 
相关问题