Comment puis-je stocker un dictionnaire avec RealmSwift?

Considérant le modèle suivant:

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

j'essaie de stocker dans le domaine un objet de type [String:String] que j'ai obtenu à partir d'un Alamofire demande, mais ne peut pas car hobbiesa à définir par let selon la Documentation RealmSwift puisque c'est un List<T>/Dictionary<T,U> type de type.

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

j'ai aussi essayé de redéfinir init() mais se retrouvait toujours avec une erreur fatale ou autrement.

Comment puis-je simplement copier ou initialiser un Un dictionnaire dans RealSwift? Est-ce que je manque quelque chose de banal ici?

18
demandé sur gabuchan 2015-11-19 08:45:14

4 réponses

Dictionary n'est pas supporté en tant que type de propriété dans Realm. Vous aurez besoin d'introduire une nouvelle classe, dont les objets décrivent chacun une clé-valeur-paire et à-beaucoup de relation à cela comme vu ci-dessous:

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

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

pour la desérialisation, vous aurez besoin de mapper votre structure de dictionnaire dans votre JSON aux objets de passe-temps et assigner la clé et la valeur à la propriété appropriée.

26
répondu marius 2015-11-19 10:27:13

je suis actuellement l'émulation ceci en exposant une propriété de dictionnaire ignorée sur mon modèle, soutenue par un privé, a persisté NSData qui encapsule une représentation JSON du dictionnaire:

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

Il pourrait ne pas être le moyen le plus efficace mais il me permet de continuer à utiliser Unbox pour mapper rapidement et facilement les données entrantes de JSON à mon modèle local de domaine.

23
répondu boliva 2016-02-27 06:14:02

je sauverais le dictionnaire comme chaîne JSON dans Realm. Ensuite, récupérez le JSON et convertissez-vous en Dictionnaire. Utilisez les extensions ci-dessous.

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

et

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"
        }
    }
}
3
répondu Ansari Awais 2017-04-27 18:42:37

peut-être un peu inefficace, mais fonctionne pour moi (exemple de dictionnaire D'Int - >chaîne, analogue pour votre exemple):

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[].val] = _values[].val };
            return ret;
         }
      }
      set {
         _keys.removeAll()
         _values.removeAll()
         _keys.appendContentsOf(newValue.keys.map({ IntObj(value: []) }))
         _values.appendContentsOf(newValue.values.map({ StringObj(value: []) }))
      }
   }
   var _keys = List<IntObj>();
   var _values = List<StringObj>();

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

Realm ne peut pas stocker une liste de chaînes / Ints parce que ce ne sont pas des objets, alors faites des "faux objets":

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

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

inspiré par une autre réponse ici sur le débordement de la pile pour stocker des tableaux de manière similaire (post m'échappe actuellement)...

2
répondu smörkex 2016-02-15 08:37:16