如何使用 RealmSwift 存储字典?

How can I store a Dictionary with RealmSwift?

考虑以下模型:

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

我正在尝试在 Realm 中存入一个类型为 [String:String] 的对象,该对象是我从 Alamofire 请求中获得的,但不能,因为 hobbies 必须 根据 RealmSwift 文档通过 let 定义,因为它是 List<T>/Dictionary<T,U> 类型。

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

我也尝试重新定义 init() 但总是以致命错误结束,否则。

如何在 RealSwift 中简单地复制或初始化字典? 我是不是遗漏了一些微不足道的东西?

Dictionary 在 Realm 中不支持 属性 类型。 您需要引入一个新的 class,其对象分别描述一个键值对和一对多关系,如下所示:

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

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

对于反序列化,您需要将 JSON 中的字典结构映射到 Hobby 对象,并将键和值分配给适当的 属性。

可能有点低效,但对我有用(来自 Int->String 的示例字典,类似于您的示例):

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[[=10=]].val] = _values[[=10=]].val };
            return ret;
         }
      }
      set {
         _keys.removeAll()
         _values.removeAll()
         _keys.appendContentsOf(newValue.keys.map({ IntObj(value: [[=10=]]) }))
         _values.appendContentsOf(newValue.values.map({ StringObj(value: [[=10=]]) }))
      }
   }
   var _keys = List<IntObj>();
   var _values = List<StringObj>();

   override static func ignoredProperties() -> [String] {
      return ["dict"];
   }
}

Realm 无法存储 Strings/Ints 的列表,因为它们不是对象,所以 "fake objects":

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

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

受这里关于堆栈溢出的另一个答案的启发,用于类似地存储数组(post 目前正在躲避我)...

我目前正在模拟这个,方法是在我的模型上公开一个被忽略的字典属性,由一个私有的、持久的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 模型。

我会在 Realm 中将字典保存为 JSON 字符串。然后检索 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"
        }
    }
}

2021 年更新

从 Realm 10.8.0 开始,可以使用 Map 类型在 Realm 对象中存储字典。

示例来自 official documentation

class Dog: Object {
    @objc dynamic var name = ""
    @objc dynamic var currentCity = ""
    // Map of city name -> favorite park in that city
    let favoriteParksByCity = Map<String, String>()
}