2015-11-19 12 views
13

Biorąc pod uwagę następujący model:Jak mogę przechowywać słownik z RealmSwift?

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

Staram się zaopatrzyć w Królestwie obiekt typu [String:String] że dostałam od żądania Alamofire ale nie mogę ponieważ hobbiesmusi być zdefiniowane przez let według do Dokumentacji RealmSwift, ponieważ jest to rodzaj typu List<T>/Dictionary<T,U>.

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

Próbowałem również przedefiniować init() ale zawsze zakończyła się fatalnym błędem lub innego.

Jak mogę po prostu skopiować lub zainicjować słownik w RealSwift? Czy brakuje tu czegoś trywialnego?

Odpowiedz

19

Dictionary nie jest obsługiwany jako typ właściwości w obszarze. trzeba by wprowadzić nową klasę, której obiekty opisać każdą kluczową wartość-pair i do-wielu, że jak widać poniżej:

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

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

Na deserializacji, trzeba by map słownika strukturę w obiektach JSON do Hobby i przypisz klucz i wartość do odpowiedniej właściwości.

+0

Dzięki! Też myślałem o tym rozwiązaniu (ponieważ jest to najczystsze), ale to naprawdę frustrujące, że nie można używać żadnych struktur Swift w RealmSwift ... (nawet krotek :(). Ponieważ moje dane są naprawdę Statyczne i proste, doszedłem do scalenia dwóch ciągów znaków razem z separatorem i utworzyłem pojedynczą listę "List '. – gabuchan

+0

Istnieją ograniczenia, które uniemożliwiają nam obsługę dowolnych ogólnych struktur Swift, szczególnie krotek.Wśród nich jest to, że musimy być w stanie określić typ w czasie wykonywania i być w stanie zwrócić wartość przez dynamiczny akcesor. To nie działa z krotkami. – marius

0

Może trochę nieskuteczny, ale pracuje dla mnie (przykład ze słownika INT> String, analogicznie do przykładu):

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 nie może przechowywać listę ciągów/Ints ponieważ te aren” t obiekty, dlatego „fałszywych obiektów”:

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

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

Zainspirowany innej odpowiedzi tutaj na przepełnienie stosu do przechowywania tablic podobnie (post jest wymyka mi obecnie) ...

19

mogę bież dost'pnych emulacji to przez poddawanie ignorowana właściwość słownik na moim modelu, wspierane przez prywatny, utrzymywały NSData który zawiera pewną reprezentację JSON słownika:

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

może nie być najbardziej skuteczny sposób, ale to pozwala mi aby nadal używać Unbox do szybkiego i łatwego mapowania przychodzących danych JSON do mojego lokalnego modelu Realm.

+0

Dzięki za udostępnienie tego. Dla mnie wygląda dobrze. –

+1

Należy zwrócić uwagę na wpływ wydajności na dodatkową procedurę serializacji JSON (de-) i utratę możliwości wykonywania zapytań w słowniku w ten sposób. – marius

+0

cześć @marius, oczywiście. Jest to obejście problemu i, jak powiedziałem, nie jest to najskuteczniejszy sposób, ale działa w przypadkach, w których muszę mieć odniesienie do słownika w mojej dziedzinie (którego nie muszę w rzeczywistości sprawdzać). Mamy nadzieję, że w pewnym momencie zobaczymy natywne wsparcie dla słowników, w którym to przypadku nie będzie to już potrzebne. – boliva

-1

Chciałbym zapisać słownik jako ciąg JSON w Królestwie. Następnie pobierz JSON i przekonwertuj na słownik. Użyj poniżej rozszerzeń.

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

i

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" 
     } 
    } 
} 
Powiązane problemy