2015-11-19 16 views
13

Considerando il seguente modello:Come posso memorizzare un dizionario con RealmSwift?

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

che sto cercando di fare scorta in Reame un oggetto di tipo [String:String] che ho ricevuto da una richiesta Alamofire ma non può in quanto hobbiesdeve da definire attraverso let secondo a RealmSwift Documentation poiché è un tipo di tipo List<T>/Dictionary<T,U>.

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

Ho anche cercato di ridefinire init() ma sempre finito con un errore fatale o altro.

Come posso semplicemente copiare o inizializzare un dizionario in RealSwift? Mi manca qualcosa di banale qui?

risposta

19

Dictionary non è supportato come tipo di proprietà in Reame. Avresti bisogno di introdurre una nuova classe, i cui oggetti descrivono ciascuno un valore di coppia di chiavi e a-molti a che, come si vede qui sotto:

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

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

Per deserializzazione, avresti bisogno di mappare il dizionario struttura nel tuo JSON agli oggetti Hobby e assegnare la chiave e il valore alla proprietà appropriata.

+0

Grazie! Ho pensato anche a questa soluzione (dato che è la più pulita) ma è davvero frustrante non poter usare le strutture Swift in RealmSwift ... (nemmeno le tuple :(). Dato che i miei dati sono davvero statico e semplice, ho finito per fondere le due stringhe insieme con un delimitatore e creato un singolo 'Elenco '. – gabuchan

+0

Ci sono dei limiti che ci impediscono di supportare qualsiasi struttura Swift generica, in particolare tuple.Tra questi ci sono che dobbiamo essere in grado di capire il tipo in fase di esecuzione ed essere in grado di restituire il valore tramite una funzione di accesso dinamica. Questo non funziona con le tuple. – marius

0

Forse un po 'inefficiente, ma funziona per me (es dizionario da INT> Stringa, analogo per il tuo esempio):

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 non è in grado di memorizzare una lista di stringhe/Ints perché questi aren' oggetti t, in modo da rendere "oggetti falsi":

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

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

Ispirato da un'altra risposta qui su stack overflow per la memorizzazione di array simile (post mi sta sfuggendo al momento) ...

19

sono cur tualmente emulando questo esponendo una proprietà Dizionario ignorato il mio modello, sostenuto da un privato, persisteva NSData che incapsula una rappresentazione JSON del dizionario:

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

Potrebbe non essere il modo più efficiente, ma mi permette per continuare a utilizzare Unbox per mappare rapidamente e facilmente i dati JSON in arrivo al modello di Realm locale.

+0

Grazie per aver condiviso questo. Mi sembra buono. –

+1

Prestare attenzione all'impatto sulle prestazioni della serializzazione JSON aggiuntiva (de-) e che si perde la possibilità di eseguire query sul dizionario in questo modo. – marius

+0

hi @marius, ovviamente. Questa è una soluzione alternativa e, come ho detto, non è il modo più efficace per farlo, ma funziona per i casi in cui ho bisogno di avere un riferimento al dizionario sul mio Reame (che non ho davvero bisogno di interrogare). Speriamo di vedere il supporto nativo per i dizionari a un certo punto, nel qual caso ciò non sarà più necessario. – boliva

-1

Vorrei salvare il dizionario come stringa JSON in Realm. Quindi riattiva il JSON e converti nel dizionario. Usa sotto le estensioni.

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

e

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