Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I store a Dictionary with RealmSwift?

Considering the following model:

class Person: Object {
    dynamic var name = ""
    let hobbies = Dictionary<String, String>()
}

I'm trying to stock in Realm an object of type [String:String] that I got from an Alamofire request but can't since hobbies has to to be defined through let according to RealmSwift Documentation since it is a List<T>/Dictionary<T,U> kind of type.

let hobbiesToStore: [String:String]
// populate hobbiestoStore
let person = Person()
person.hobbies = hobbiesToStore

I also tried to redefine init() but always ended up with a fatal error or else.

How can I simply copy or initialize a Dictionary in RealSwift? Am I missing something trivial here?

like image 268
gabuchan Avatar asked Nov 19 '15 05:11

gabuchan


3 Answers

Dictionary is not supported as property type in Realm. You'd need to introduce a new class, whose objects describe each a key-value-pair and to-many relationship to that as seen below:

class Person: Object {
    dynamic var name = ""
    let hobbies = List<Hobby>()
}

class Hobby: Object {
    dynamic var name = ""
    dynamic var descriptionText = ""
}

For deserialization, you'd need to map your dictionary structure in your JSON to Hobby objects and assign the key and value to the appropriate property.

like image 170
marius Avatar answered Nov 14 '22 02:11

marius


I am currently emulating this by exposing an ignored Dictionary property on my model, backed by a private, persisted NSData which encapsulates a JSON representation of the dictionary:

class Model: Object {
    private dynamic var dictionaryData: NSData?
    var dictionary: [String: String] {
        get {
            guard let dictionaryData = dictionaryData else {
                return [String: String]()
            }
            do {
                let dict = try NSJSONSerialization.JSONObjectWithData(dictionaryData, options: []) as? [String: String]
                return dict!
            } catch {
                return [String: String]()
            }
        }

        set {
            do {
                let data = try NSJSONSerialization.dataWithJSONObject(newValue, options: [])
                dictionaryData = data
            } catch {
                dictionaryData = nil
            }
        }
    }

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

It might not be the most efficient way but it allows me to keep using Unbox to quickly and easily map the incoming JSON data to my local Realm model.

like image 40
boliva Avatar answered Nov 14 '22 01:11

boliva


I would save the dictionary as JSON string in Realm. Then retrive the JSON and convert to dictionary. Use below extensions.

extension String{
func dictionaryValue() -> [String: AnyObject]
{
    if let data = self.data(using: String.Encoding.utf8) {
        do {
            let json = try JSONSerialization.jsonObject(with: data, options: JSONSerialization.ReadingOptions.allowFragments) as? [String: AnyObject]
            return json!

        } catch {
            print("Error converting to JSON")
        }
    }
    return NSDictionary() as! [String : AnyObject]
} }

and

extension NSDictionary{
    func JsonString() -> String
    {
        do{
        let jsonData: Data = try JSONSerialization.data(withJSONObject: self, options: .prettyPrinted)
        return String.init(data: jsonData, encoding: .utf8)!
        }
        catch
        {
            return "error converting"
        }
    }
}
like image 38
Ansari Awais Avatar answered Nov 14 '22 01:11

Ansari Awais