Allen.L
Allen.L

Reputation: 93

How to map different type using ObjectMapper?

I'm using ObjectMapper to map my JSON to Swift object.

I have the following Swift object:

class User: Mappable {

    var name: String?
    var val: Int?

    required init?(map: Map) { }

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

I have this JSON structure:

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

After mapping the JSON, the userId of User which name is "first" is null.

How can I map Int/String to Int?

Upvotes: 1

Views: 4186

Answers (3)

Allen.L
Allen.L

Reputation: 93

After reading the code of ObjectMapper, I found an easier way to solve the problem, it's to custom the 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)
    }
}

then, use the custom transform to the mapping function.

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

Hope it can help others who have the same problem. :)

Upvotes: 6

Anh Pham
Anh Pham

Reputation: 2118

You should improve your API. However, if you can't do that, then try this code:

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

You can refer to this document: Type Casting

Upvotes: 1

Miknash
Miknash

Reputation: 7948

If your API is like this - it is very bad API. What you could do is have two variables instead of one:

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"]
    }
}

You can even add function that will get you value like:

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

Or, using if let:

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

Or using optionals so later on you can use if let userId = object.getUserId()

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

Upvotes: 1

Related Questions