Alamofire, Objectmapper, Realm: Nested Objects

风流意气都作罢 提交于 2019-12-01 07:32:12

The old ListTransform solution no longer works in Swift 3.

This is what I'm using now; put this in a file called, ListExtensions.swift, for example.

import Foundation
import ObjectMapper
import RealmSwift

/// Maps object of Realm's List type
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)
        }
    }
}

This allows you to simply use it like this:

class Parent: Object, Mappable {
    dynamic var id: Int = 0
    var children = List<Child>()

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

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

The problem you're seeing is due to ObjectMapper having no knowledge of Realm's List type. It is not aware that it is a collection type, and that it must be mutated in place rather than being assigned to. You can see discussion of this, including some suggested workarounds, in ObjectMapper GitHub issue #143.

Note also that any List properties on Object subclasses should be declared with let rather than var.

class ListTransform<T:RealmSwift.Object> : TransformType where T:Mappable {
    typealias Object = List<T>
    typealias JSON = [AnyObject]

    let mapper = Mapper<T>()

    func transformFromJSON(_ value: Any?) -> Object? {
        let results = List<T>()
        if let objects = mapper.mapArray(JSONObject: value) {
            for object in objects {
                results.append(object)
            }
        }
        return results
    }

    func transformToJSON(_ value: Object?) -> JSON? {
        var results = [AnyObject]()
        if let value = value {
            for obj in value {
                let json = mapper.toJSON(obj)
                results.append(json as AnyObject)
            }
        }
        return results
    }
}

Then in your model something like this.

class Parent: Object, Mappable {
    dynamic var id: Int = 0
    var children = List<Child>()

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

    func mapping(map: Map) {
        id <- map["id"]
        child <- (map["children"], ListTransform<Child>())
    }
}

You can extend ObjectMapper for Realm.List type with a operator function like as:

public func <- <T: Object where T: Mappable, T: JSPrimaryKey>(left: List<T>, right: Map) {
  if right.mappingType == MappingType.FromJSON {
    if let value = right.currentValue {
      left.removeAll()
      if let json = value as? [[String : AnyObject]] {
        let objs = RealmS().add(T.self, json: json)
        left.appendContentsOf(objs)
      }
    }
  }
}

Try yourself.

ObjectMappper + Realm List type

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!