Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

RealmSwift + ObjectMapper managing String Array (tags)

What I need to represent in RealmSwift is the following JSON scheme:

{ 
    "id": 1234,
    "title": "some value",
    "tags": [ "red", "blue", "green" ]
}

Its a basic string array that I'm stumbling on. I'm guessing in Realm I need to represent "tags" as

dynamic id: Int = 0
dynamic title: String = ""
let tags = List<MyTagObject>()

making tags its own table in Realm, but how to map it with ObjectMapper? This is how far I got...

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

... but the tags line doesn't compile of course because of the List and Realm cannot use a [String] type.

This feels like a somewhat common problem and I'm hoping someone who has faced this can comment or point to a post with a suggestion.

UPDATE 1 The MyTagObject looks like the following:

class MyTagObject: Object {
    dynamic var name: String = ""
}

UPDATE 2 I found this post which deals with the realm object but assumes the array has named elements rather than a simple string. https://gist.github.com/Jerrot/fe233a94c5427a4ec29b

like image 213
darren Avatar asked Jan 01 '26 18:01

darren


2 Answers

My solution is to use an ObjectMapper TransformType as a custom method to map the JSON to a Realm List<String> type. No need for 2 Realm models.

Going with your example JSON:

{ 
    "id": 1234,
    "title": "some value",
    "tags": [ "red", "blue", "green" ]
}
  1. First, create an ObjectMapper TransformType object:
import Foundation
import ObjectMapper
import RealmSwift

public struct StringArrayTransform: TransformType {

    public init() { }

    public typealias Object = List<String>
    public typealias JSON = [String]

    public func transformFromJSON(_ value: Any?) -> List<String>? {
        guard let value = value else {
            return nil
        }
        let objects = value as! [String] 
        let list = List<String>()
        list.append(objectsIn: objects)
        return list
    }

    public func transformToJSON(_ value: Object?) -> JSON? {
        return value?.toArray()
    }

}

  1. Create your 1 Realm model used to store the JSON data:
import Foundation
import RealmSwift
import ObjectMapper

class MyObjectModel: Object, Mappable {

    @objc dynamic id: Int = 0
    @objc dynamic title: String = ""
    let tags = List<MyTagObject>()

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

    func mapping(map: Map) {
        id <- map["id"]
        title <- map["title"]
        tags <- (map["tags"], StringArrayTransform())
    }

}

Done!

This line is the magic: tags <- (map["tags"], StringArrayTransform()). This tells ObjectMapper to use our custom StringArrayTransform I showed above which takes the JSON String array and transforms it into a Realm List<String>.

like image 133
levibostian Avatar answered Jan 04 '26 15:01

levibostian


First of all we should assume that our model extends both Object and Mappable.

Let's create a wrapper model to store the primitive (String) type:

class StringObject: Object {
    dynamic var value = ""
}

Then we describe corresponding properties and mapping rules for the root model (not the wrapper one):

var tags = List<StringObject>()

var parsedTags: [String] {
    var result = [String]()
    for tag in tags {
        result.append(tag.value)
    }
    return result
}

override static func ignoredProperties() -> [String] {
    return ["parsedTags"]
}

func mapping(map: Map) {
    if let unwrappedTags = map.JSON["tags"] as? [String] {
        for tag in unwrappedTags {
            let tagObject = StringObject()
            tagObject.value = tag
            tags.append(tagObject)
        }
    }
}

We need a tags property to store and obtain the data about tags from Realm. Then a parsedTags property simplifies extraction of tags in the usual array format. An ignoredProperties definition allows to avoid some failures with Realm while data savings (because of course we can't store non-Realm datatypes in the Realm). And at last we are manually parsing our tags in the mapping function to store it in the Realm.

like image 37
Andrei K. Avatar answered Jan 04 '26 15:01

Andrei K.



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!