How can I store a Dictionary with RealmSwift?

谁说我不能喝 提交于 2020-12-27 08:41:53

问题


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?


回答1:


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.




回答2:


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.




回答3:


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



回答4:


Perhaps a little inefficient, but works for me (example dictionary from Int->String, analogous for your example):

class DictObj: Object {
   var dict : [Int:String] {
      get {
         if _keys.isEmpty {return [:]} // Empty dict = default; change to other if desired
         else {
            var ret : [Int:String] = [:];
            Array(0..<(_keys.count)).map{ ret[_keys[$0].val] = _values[$0].val };
            return ret;
         }
      }
      set {
         _keys.removeAll()
         _values.removeAll()
         _keys.appendContentsOf(newValue.keys.map({ IntObj(value: [$0]) }))
         _values.appendContentsOf(newValue.values.map({ StringObj(value: [$0]) }))
      }
   }
   var _keys = List<IntObj>();
   var _values = List<StringObj>();

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

Realm can't store a List of Strings/Ints because these aren't objects, so make "fake objects":

class IntObj: Object {
   dynamic var val : Int = 0;
}

class StringObj: Object {
   dynamic var val : String = "";
}

Inspired by another answer here on stack overflow for storing arrays similarly (post is eluding me currently)...



来源:https://stackoverflow.com/questions/33796143/how-can-i-store-a-dictionary-with-realmswift

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