Skip to content

Better Mappable through Property Wrappers using ObjectMapper

License

Notifications You must be signed in to change notification settings

PhonePe/BetterMappable

Repository files navigation

BetterMappable

Swift 5.1 CocoaPods Carthage compatible Swift Package Manager

Better Mappable utilising Swift 5 Property Wrappers is a ÎĽframework written on top of ObjectMapper that makes it easy to convert model objects (classes and structs) to and from JSON. Results in reduction of a lot of boiler plate code in models.

Index

JSONProperty

Utilise this property wrapper to map any primitive variables (Int, String, Bool etc...)

struct User: Mappable {
    @JSONProperty var name: String?
    @JSONProperty var age: Int?
    @JSONProperty var onPhonePe: Bool?

    init?(map: Map) {
    }
}

That's it! For those who are familiar with ObjectMapper, yes, you do not have to implement func mapping(map: Map) at all. We automatically take the variable name and assign right value from/to JSON. Incase your variable name is different from the key in the JSON, you can provide it as a parameter in JSONProperty.

@JSONProperty(key: "on_phonepe") 
var onPhonePe: Bool?

You can provide default value to a variable like the way you generally do with ObjectMapper.

@JSONProperty 
var age: Int = 0
    
@JSONProperty(key: "on_phonepe")
var onPhonePe: Bool = false

JSONObject

Use this property wrapper to map custom classes/structs which confirms to Mappable protocol

struct Student: Mappable {
    @JSONObject var address: Address?
    
    @JSONProperty var firstName: String?
    @JSONProperty var lastName: String?
    
    init?(map: Map) {
    }
}

struct Address: Mappable {
    @JSONProperty var street: String?
    @JSONProperty var building: String?
    @JSONProperty var city: String?
    @JSONProperty var state: String?
    
    init?(map: Map) {
        
    }
}

Like the JSONProperty example, if your variable name is different from the key in the JSON, you can provide it as a parameter in JSONObject.

@JSONObject(key: "student_address") 
var address: Address?

JSONObjectArray

Use this property wrapper to map array of custom classes/structs which confirms to Mappable protocol

struct Store: Mappable {
    @JSONObjectArray var transactions: [Transaction]?
    
    @JSONProperty var name: String?
    
    init?(map: Map) {
    }
}

struct Transaction: Mappable {
    @JSONProperty var id: String?
    
    @JSONProperty var amount: Int = 0
    
    init?(map: Map) {
    }
}

JSONObjectDictionary

Use this property wrapper to map dictionary of custom classes/structs which confirms to Mappable protocol

struct Categories: Mappable {
    @JSONObjectDictionary var data: [String: Category]?
    
    init?(map: Map) {
    }
}

struct Category: Mappable {
    @JSONProperty var id: String?
    @JSONProperty var name: String?
    
    init?(map: Map) {
    }
}

JSONObjectDictionaryArrayValue

Use this property wrapper to map dictionary of custom array classes/structs which confirms to Mappable protocol

struct Categories: Mappable {
    @JSONObjectDictionaryArrayValue var data: [String: [Category]]?
    
    init?(map: Map) {
    }
}

struct Category: Mappable {
    @JSONProperty var id: String?
    @JSONProperty var name: String?
    
    init?(map: Map) {
    }
}

JSONPropertyWithTransform

Use this property wrapper to map variables with transformation.

struct Organization: Mappable {
    enum Sector: String {
        case `private` = "PRIVATE"
        case `public` = "PUBLIC"
    }
    
    @JSONPropertyWithTransform(transformer: DateTransform())
    var startDate: Date?
    
    @JSONPropertyWithTransform(transformer: EnumTransform<Sector>())
    var sector: Sector?
    
    @JSONProperty var name: String?
    
    init?(map: Map) {
    }
}

Does this work with StaticMappable?`

Yes it does.

class Vehicle {
    enum VehicleType: String {
        case car = "CAR"
        case bicycle = "BICYCLE"
    }
    
    @JSONProperty var numberOfWheels: Int?
}

extension Vehicle: StaticMappable {
    static func objectForMapping(map: Map) -> BaseMappable? {
        if let rawType = map.JSON["type"] as? String,
            let type = VehicleType(rawValue: rawType) {
            switch type {
            case .car:
                return Car()
                
            case .bicycle:
                return Bicycle()
            }
        }
        
        return nil
    }
}

class Car: Vehicle {
    @JSONProperty var hasBonet: Bool?
}

class Bicycle: Vehicle {
    @JSONProperty var modelName: String?
}

Subclasses

class Base: Mappable {
    @JSONProperty var base: String?
    
    required init?(map: Map) {
    }
}

class Subclass: Base {
    @JSONProperty var sub: String?

    required init?(map: Map) {
        super.init(map: map)
    }
}

Installation

CocoaPods

CocoaPods is a dependency manager for Cocoa projects. For usage and installation instructions, visit their website. To integrate BetterMappable into your Xcode project using CocoaPods, specify it in your Podfile:

pod 'BetterMappable', '~> 1.0'

Carthage

Carthage is a decentralized dependency manager that builds your dependencies and provides you with binary frameworks. To integrate BetterMappable into your Xcode project using Carthage, specify it in your Cartfile:

github "PhonePe/BetterMappable" "1.0.1"

Swift Package Manager

The Swift Package Manager is a tool for automating the distribution of Swift code and is integrated into the swift compiler. It is in early development, but BetterMappable does support its use on supported platforms.

Once you have your Swift package set up, adding BetterMappable as a dependency is as easy as adding it to the dependencies value of your Package.swift.

dependencies: [
    .package(url: "https://github.com/PhonePe/BetterMappable.git", .upToNextMajor(from: "1.0.0"))
]

Credits

Srikanth KV