2015-11-19 2 views
13

Учитывая следующую модель:Как я могу хранить словарь с помощью RealmSwift?

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

Я пытаюсь запасти в Realm объект типа [String:String], который я получил от запроса Alamofire, но не может, так как hobbiesимеет в быть определен через let по в RealmSwift Documentation, так как это тип типа List<T>/Dictionary<T,U>.

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

Я также попытался переопределить init(), но всегда в конечном итоге с фатальной ошибкой или еще.

Как я могу просто скопировать или инициализировать словарь в RealSwift? Я пропустил что-то тривиальное здесь?

ответ

19

Dictionary не поддерживается как тип недвижимости в Realm. Вам потребуется ввести новый класс, объекты которого описывают каждый ключ-значение-пара и ко многим к тому, что, как показано ниже:

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

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

Для десериализации, вам необходимо сопоставить словарь структуру в ваших объектах JSON для хобби и присвоить ключ и значение соответствующему свойству.

+0

Спасибо! Я тоже подумал об этом решении (так как это самый чистый), но просто неудобно не использовать любые структуры Swift в RealmSwift ... (даже не кортежи :(). Как мои данные действительно статические и простые, я завершил слияние двух строк вместе с разделителем и создал один «Список ». – gabuchan

+0

Существуют ограничения, которые мешают нам поддерживать любые общие структуры Swift, особенно кортежи.Среди них мы должны уметь определять тип во время выполнения и иметь возможность вернуть значение динамическим аксессуаром. Это не работает с кортежами. – marius

0

Может быть, немного неэффективно, но работает для меня (пример словаря из Int-> Строка, аналогично для примера):

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 не может хранить список строк/Ints, потому что они Арен» т объекты, так что «поддельные предметы»:

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

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

Вдохновленный другой ответ здесь на переполнение стека для хранения массивов так же (пост ускользает меня в настоящее время) ...

19

меня дворняжка rently эмуляции это путем воздействия на проигнорировано словарь свойства на моей модели, опираясь на частный, сохранялись NSData который инкапсулирует представление JSON словаря:

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

Это может быть не самым эффективным способом, но это позволяет мне продолжать использовать Unbox, чтобы быстро и легко отображать входящие данные JSON в мою локальную модель Realm.

+0

Спасибо, что поделились этим. Выглядит хорошо. –

+1

Помните о влиянии производительности на дополнительную сериализацию JSON (de-) и вы теряете возможность запроса по словарю таким образом. – marius

+0

привет @marius, конечно. Это обходной путь и, как я уже говорил, не самый эффективный способ сделать это, но он работает для тех случаев, когда мне нужно иметь ссылку на словарь в моем Царстве (что мне действительно не нужно запрашивать). Надеюсь, в какой-то момент мы увидим поддержку родных словарей, и в этом случае это больше не понадобится. – boliva

-1

Я бы сохранил словарь как строку JSON в Realm. Затем загрузите JSON и конвертируйте в словарь. Используйте ниже расширения.

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

и

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" 
     } 
    } 
} 
Смежные вопросы