web-dev-qa-db-fra.com

Comment puis-je stocker un dictionnaire avec RealmSwift?

En considérant le modèle suivant:

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

J'essaie de stocker dans Realm un objet de type [String:String] Que j'ai reçu d'une demande Alamofire mais que je ne peux pas depuis hobbiesdoit être défini via let selon la documentation de RealmSwift car il s'agit d'un type de type List<T>/Dictionary<T,U>.

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

J'ai également essayé de redéfinir init() mais je me retrouvais toujours avec une erreur fatale ou autre.

Comment puis-je simplement copier ou initialiser un dictionnaire dans RealSwift? Suis-je en train de manquer quelque chose de trivial ici?

22
gabuchan

Dictionary n'est pas pris en charge comme type de propriété dans Realm. Vous auriez besoin d'introduire une nouvelle classe, dont les objets décrivent chacun une paire clé-valeur et une relation à plusieurs comme celle ci-dessous:

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

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

Pour la désérialisation, vous devez mapper la structure de votre dictionnaire dans votre JSON aux objets Hobby et affecter la clé et la valeur à la propriété appropriée.

32
marius

J'émule actuellement ceci en exposant une propriété Dictionary ignorée sur mon modèle, soutenue par un NSData persistant privé 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"]
    }
}

Ce n'est peut-être pas le moyen le plus efficace, mais cela me permet de continuer à utiliser nbox pour mapper rapidement et facilement les données JSON entrantes à mon modèle de domaine local.

26
boliva

Je voudrais enregistrer le dictionnaire en tant que chaîne JSON dans Realm. Récupérez ensuite le JSON et convertissez-le 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"
        }
    }
}
4
Ansari Awais

Peut-être un peu inefficace, mais fonctionne pour moi (exemple de dictionnaire de Int-> String, analogue à 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[$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"];
   }
}

Le royaume ne peut pas stocker une liste de chaînes/entiers car 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 pile pour stocker les tableaux de la même manière (le message m'échappe actuellement) ...

2
smörkex