Search code examples
iosswiftreflectionobjectmapper

ObjectMapper: Using reflection in map function


I am using ObjectMapper for a while and I find it cumbersome to write map function for classes with lots of property by using the way described in documents:

func mapping(map: Map) {
    username    <- map["username"]
    age         <- map["age"]
    weight      <- map["weight"]
    array       <- map["array"]
    dictionary  <- map["dictionary"]
    bestFriend  <- map["bestFriend"]
    friends     <- map["friends"]
}

I wonder if it is possible to use reflection to write map function like below assuming my JSON data and my class have axactly same property names:

func mapping(map: Map) {
    let names = Mirror(reflecting: self).children.flatMap { $0.label }
    for name in names {
        self.value(forKey: name) <- map[name]
    }
}

UPDATE:

Based on Sweeper's answer I have updated my code:

func mapping(map: Map) {
    for child in Mirror(reflecting: self).children.compactMap({$0}) {
        child <- map[child.label]
    }
}

I guess this should work.

UPDATE 2:

Thanks to Sweeper, I have find out my initial guess was wrong and Child is just a typealias for a touple:

public typealias Child = (label: String?, value: Any)

So my second attempt is also won't work.


Solution

  • The <- operator is declared like this:

    public func <- <T: RawRepresentable>(left: inout T, right: Map) {
        left <- (right, EnumTransform())
    }
    

    As you can see, the left parameter is declared inout. This means that you must use a mutable variable there, not the return value of some method.

    So you do need to write all the properties.

    I found this plugin that generates the mapping for you: https://github.com/liyanhuadev/ObjectMapper-Plugin

    In Swift 4, Codable is introduced and yet automatically works things out for you:

    struct Foo: Codable {
        var username: String
        var age: Int
        var weight: Double
    
        // everything is done for you already! You don't need to write anything else
    }