Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Easy mapping Realm's List and RealmOptional with ObjectMapper

This code helps using ObjectMapper with RealmSwift.

RealmSwift uses List<T> collection for "to many" relashionships and RealmOptional<T> for optional primitive types, but ObjectMapper can't map directly to List<T> and RealmOptional<T>.

With this operators you can properly define RealmSwift's relashionships and optional properties and use <- operator to map them.

Example

import Foundation
import RealmSwift
import ObjectMapper

class Chat: Object, Mappable {

    let messages = List<Message>()

    func mapping(map: Map) {
        // use <- operator to map a List
        messages <- map["messages"]
    }

    required convenience init?(map: Map) {
        self.init()
    }
    
}

class Message: Object, Mappable {

    dynamic var text: String? = nil

    let length = RealmOptional<Int>()

    func mapping(map: Map) {
        text <- map["text"]
        // use <- operator to map a RealmOptional
        length <- map["length"]
    }

    required convenience init?(map: Map) {
        self.init()
    }
    
}

Swift 3

import Foundation
import RealmSwift
import ObjectMapper

infix operator <-

/// Object of Realm's List type
public func <- <T: Mappable>(left: List<T>, right: Map) {
    var array: [T]?

    if right.mappingType == .toJSON {
        array = Array(left)
    }

    array <- right

    if right.mappingType == .fromJSON {
        if let theArray = array {
            left.append(objectsIn: theArray)
        }
    }
}

/// Object of Realm's RealmOptional type
public func <- <T>(left: RealmOptional<T>, right: Map) {
    var optional: T?

    if right.mappingType == .toJSON {
        optional = left.value
    }

    optional <- right

    if right.mappingType == .fromJSON {
        if let theOptional = optional {
            left.value = theOptional
        }
    }
}

Swift 2

infix operator <- {}

/// Object of Realm's List type
public func <- <T: Mappable>(left: List<T>, right: Map) {
    var array: [T]?

    if right.mappingType == .ToJSON {
        array = Array(left)
    }

    array <- right

    if right.mappingType == .FromJSON {
        if let theArray = array {
            left.appendContentsOf(theArray)
        }
    }
}

/// Object of Realm's RealmOptional type
public func <- <T>(left: RealmOptional<T>, right: Map) {
    var optional: T?

    if right.mappingType == .ToJSON {
        optional = left.value
    }

    optional <- right

    if right.mappingType == .FromJSON {
        if let theOptional = optional {
            left.value = theOptional
        }
    }
}
@kdawgwilk

This comment has been minimized.

Copy link

commented Oct 12, 2016

By using this we have to change our List properties from let (Realm recommends) to var will this have any side effects?

@danilValeev

This comment has been minimized.

Copy link
Owner Author

commented Oct 18, 2016

@kdawgwilk The pros of this approach is that you have not to change a List properties from let to var. It is not recommended.

@RajaveluC

This comment has been minimized.

Copy link

commented Dec 21, 2016

@danilValeev

I am using the above swift 3.0 and I have added your file to my project, and I still couldn't get around parsing nested objects successfully.

What is wrong here?

Here are my classes.

class User : Object, Mappable {

    dynamic var userId: String!
    dynamic var emailId: String!
    
    override class func primaryKey() -> String? {
        return "userId"
    }
    
    required convenience init?(map: Map) {
        self.init()
    }
    
    func mapping(map: Map) {
        userId <- map["userId"]
        emailId <- map["email"]
    }
}

class ContactGroup : Object, Mappable {
    dynamic var groupId: String!
    var users = List<User> ()
    
    override class func primaryKey() -> String? {
        return "groupId"
    }
    
    required convenience init?(map: Map) {
        self.init()
    }
    
    func mapping(map: Map) {
        groupId <- map["contactGroupId"]
        users <- map["users"]
    }
}

func storeContactGroups (groups : NSArray)  {
        var groupRealms = Array<ContactGroup> ()
        for object in groups {
            let group : ContactGroup! = ContactGroup(JSON: object as! [String : Any])
            groupRealms.append(group)
        }
        
        let realm = try! Realm()
        try! realm.write {
            for group in groupRealms {
                realm.add(group, update: true)
            }
        }
 }

After the storeContactGroups is executed, I still see zero Users in my Realm file under ContactGroup. What am I doing wrong here?

screen shot 2016-12-21 at 2 52 23 pm

@kubatruhlar

This comment has been minimized.

Copy link

commented Feb 15, 2017

Not working with Swift 3, array <- right will produce nil. (list type)

@danilValeev

This comment has been minimized.

Copy link
Owner Author

commented Feb 22, 2017

@RajaveluC Have you found an issue? Can you provide json example?

@danilValeev

This comment has been minimized.

Copy link
Owner Author

commented Feb 22, 2017

@kubatruhlar Works for me. There are two parts: first is for Swift 3. Can you provide the code that doesn't work?

@madawei2699

This comment has been minimized.

Copy link

commented Oct 13, 2017

@kubatruhlar The List(), the Object must confirm Mappable class.

@artem-shmatkov

This comment has been minimized.

Copy link

commented Jan 19, 2018

@danilValeev, Thanks, really helpful!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.