2015-11-19 10 views
13

das folgende Modell Betrachtet:Wie kann ich ein Wörterbuch mit RealmSwift speichern?

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

Ich versuche [String:String], die ich von einem Alamofire Anfrage bekam in Realm ein Objekt vom Typ einzudecken, kann aber nicht, da hobbieszu wurde nach durch let zu definierende zu RealmSwift Documentation, da es ein List<T>/Dictionary<T,U> Art von Typ ist.

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

Ich habe auch versucht init() neu zu definieren, aber immer mit einem schwerwiegenden Fehler oder auch am Ende.

Wie kann ich einfach ein Wörterbuch in RealSwift kopieren oder initialisieren? Fehle mir hier etwas Triviales?

Antwort

19

Dictionary wird nicht als Eigenschaftstyp in Realm unterstützt. Sie müßten eine neue Klasse einführen, deren Objekte beschreiben jeweils ein Schlüssel-Wert-Paar und n-Beziehung zu, dass wie unten zu sehen:

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

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

Für Deserialisierung, müssen Sie Ihren Wörterbuch kartieren Strukturieren Sie in Ihrem JSON zu Hobby-Objekten und weisen Sie den Schlüssel und den Wert der entsprechenden Eigenschaft zu.

+0

Dank! Ich habe auch an diese Lösung gedacht (da es die sauberste ist), aber es ist wirklich frustrierend, keine Swift-Strukturen in RealmSwift zu verwenden ... (nicht einmal Tupel :(). Wie meine Daten wirklich sind statisch und einfach, habe ich die beiden Strings mit einem Delimiter verschmolzen und eine einzelne "List " erstellt. – gabuchan

+0

Es gibt Einschränkungen, die uns davon abhalten, generische Swift-Strukturen, insbesondere Tupel, zu unterstützen.Dazu gehört, dass wir in der Lage sein müssen, den Typ zur Laufzeit herauszufinden und den Wert durch einen dynamischen Accessor zurückgeben zu können. Das funktioniert nicht mit Tupeln. – marius

0

Vielleicht ein wenig ineffizient, sondern arbeitet für mich (zB Wörterbuch von Int-> String, analog für Ihr Beispiel):

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 kann nicht speichern Sie eine Liste der Strings/Ints weil diese aren‘ t Objekte, so machen "gefälschte Objekte":

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

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

Inspiriert von einer anderen Antwort hier auf Stack-Überlauf für Arrays in ähnlicher Weise zu speichern (Post ist ich zur Zeit eluding) ...

19

ich bin cur Beauty Preisliste diese durch Belichtung eines ignoriert Wörterbuch Eigenschaft auf meinem Modell zu emulieren, die von einem privaten gesichert, beharrte NSData, die eine JSON Darstellung des Wörterbuchs kapselt:

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

Es ist nicht der effizienteste Weg sein könnte, aber es erlaubt mir weiterhin Unbox verwenden, um die eingehenden JSON-Daten schnell und einfach meinem lokalen Realm-Modell zuzuordnen.

+0

Danke für das Teilen. Sieht gut für mich aus. –

+1

Bitte beachten Sie die Auswirkungen auf die Performance durch die zusätzliche JSON (De-) Serialisierung und dass Sie die Möglichkeit verlieren, das Wörterbuch auf diese Weise abzufragen. – marius

+0

hi @ marius, natürlich. Dies ist eine Problemumgehung und, wie gesagt, nicht die effizienteste Art, es zu tun, aber es funktioniert für die Fälle, wo ich eine Wörterbuchreferenz auf meinem Realm haben muss (die ich wirklich nicht abfragen muss). Hoffentlich werden wir irgendwann die native Unterstützung für Wörterbücher sehen können. In diesem Fall wird dies nicht mehr benötigt. – boliva

-1

Ich würde das Wörterbuch als JSON-Zeichenfolge in Realm speichern. Dann retrive das JSON und konvertiere in das Wörterbuch. Verwenden Sie unter Erweiterungen.

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

und

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