Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to map a realm list of custom objects using Mappable protocol in Swift

In my Realm object model I have an object called "Event". Each Event has a list of EventLocatons. I am trying to map these object from json, but the list of EventLocations is always empty. The objects look like this (simplified for clarity):

class Event: Object, Mappable {
    override class func primaryKey() -> String? {
        return "id"
    }

    dynamic var id = "" 
    var eventLocations:List<EventLocation> = List<EventLocation>()

    func mapping(map: Map) {
        id <- map["id"]
        eventLocations <- map["eventLocations"]
    }
}

class EventLocation: Object, Mappable {
    override class func primaryKey() -> String? {
        return "id"
    }

    dynamic var id: String = ""
    dynamic var name: String = ""

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

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

The json, that I have is an array of Event objects. It comes from an Alamofire response and I map it like that:

var events = Mapper<Event>().mapArray(json!)

The json looks like this:

[
  {
    "id" : "21dedd6d",
    "eventLocations" : [
      {
        "name" : "hh",
        "id" : "e18df48a",
       },
      {
        "name" : "tt",
        "fileId" : "be6116e",
      }
    ]
  },
  {
    "id" : "e694c885",
    "eventLocations" : [
      {
        "name" : "hh",
        "id" : "e18df48a",
       },
      {
        "name" : "tt",
        "fileId" : "be6116e",
      }
    ]
  }
 ]

Does anyone know how can I map a list of custom objects using the Mappable protocol. Whay is the "eventLocations" list always empty?

like image 652
hmitkov Avatar asked Jun 30 '16 07:06

hmitkov


3 Answers

You can add an operator for this.

Swift 3 implementation:

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

Now you don't need any additional code or transforms.

list <- map["name"]

I've created a gist. Please, check https://gist.github.com/danilValeev/ef29630b61eed510ca135034c444a98a

like image 160
Danil Valeev Avatar answered Nov 09 '22 11:11

Danil Valeev


Having a look at one of the Issues page on ObjectMapper's GitHub repo, it doesn't look like Realm List objects are properly supported yet.

That issue also lists a potential workaround for getting it to work for the time being, which I'll mirror here:

class MyObject: Object, Mappable {
    let tags = List<Tag>()

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

    func mapping(map: Map) {
        var tags: [Tag]?
        tags <- map["tags"]
        if let tags = tags {
            for tag in tags {
                self.tags.append(tag)
            }
        }
    }
}
like image 37
TiM Avatar answered Nov 09 '22 11:11

TiM


Another solution could be to implement a custom transform for ObjectMapper. You can find an implementation here.

Then in your code:

eventLocations <- (map["eventLocations"], ListTransform<EventLocation>())
like image 4
Thanh Pham Avatar answered Nov 09 '22 12:11

Thanh Pham