【问题标题】:How to properly map JSON properties to model properties in Realm.create如何正确地将 JSON 属性映射到 Realm.create 中的模型属性
【发布时间】:2015-11-29 14:26:57
【问题描述】:

我目前正在通过调用realm.create(T.self, value: object, update: true) 使用 Realm 实现插入或更新模式。 object 是从 rest 调用返回的 JSON,它可能包含与该领域对象关联的部分或全部属性。 (也就是说,我需要支持部分更新。)

在许多 JSON 对象中都有一个名为 description 的键。由于我不能拥有一个具有名为public dynamic var description 的属性的领域对象子类,我需要选择另一个名称并确保在调用realm.create 时正确映射它。我知道你在想什么,我可以在调用 create 之前进行映射。然而,JSON 也可能有嵌套对象/对象数组,当 Realm 已经知道这些对象映射到哪里时,为所有嵌套属性设置映射对我来说似乎是多余的。如果我可以简单地在每个 Object 子类中定义一个映射,然后 Realm 可以计算出其余部分,那会更简洁。

我解决此问题的第一次尝试是覆盖 Objectinit 函数(即使 cmets 明确表示不这样做,也必须尝试),但这不起作用,因为没有任何 init 方法接受 JSON对象实际上是使用realm.create 调用的。

有什么方法可以让我的生活更轻松吗?

注意:我使用的是 Swift 2.0 和 Realm 的 swift-2.0 分支

【问题讨论】:

标签: swift realm


【解决方案1】:

Realm 在使用 Swift 时仍然不支持正确的映射,所以让我详细说明 jpsim 注释。

ObjectMapper 提供了强大的映射机制,不仅可以让您选择模型属性名称,还可以很好地处理您在映射过程中可能需要的任何清理。

这是我为dummy project 编写的示例:

import ObjectMapper

class Color: RLMObject, Mappable{

    dynamic var myId = 0
    dynamic var myTitle = ""
    dynamic var username = ""
    dynamic var hex = ""

    override static func primaryKey() -> String?{
        return "id"
    }

    required convenience init?(_ map: Map){
        self.init()
    }

    static func mappedColor(dict:Dictionary<String, AnyObject>) -> Color{
        return Mapper<Color>().map(dict)! as Color
    }

    func mapping(map: Map) {
        id <- map["id"]
        title <- map["title"]
        username <- map["userName"]
        hex <- map["hex"]
    }
}

您可以看到我有一个链接到 ObjectMapper Mappable 协议的 mapping 函数,以及一个 mappedColor 函数,它只不过是一种映射 JSON 以检索我的模型对象的便捷方法。

然后我可以在 web 服务调用响应中使用它:

[...]
if let JSON:Array = response.result.value as? Array<[String: AnyObject]> {

    do{
        try RLMRealm.defaultRealm().transactionWithBlock {
            for dict in JSON{
                let color = Color.mappedColor(dict)
                RLMRealm.defaultRealm().addOrUpdateObject(color)
            }
        }
    } catch let error as NSError {
        print(error)
    }
}
[...]

【讨论】:

    【解决方案2】:

    您也可以使用SwiftyJSONModel。领域模型看起来像这样:

    final class Person: Object {
        dynamic var name = ""
        dynamic var age = ""
        dynamic var isMarried = false
    }
    
    extension Person: JSONObjectInitializable {
        enum PropertyKey: String {
            case name, age, isMarried
        }
    
        convenience init(object: JSONObject<PropertyKey>) throws {
            self.init()
            name = try object.value(for: .name)
            age = try object.value(for: .age)
            isMarried = try object.value(for: .isMarried)
        }
    }
    

    这个框架有一些不错的特性,比如:

    1. 键都封装在枚举中,因此您会收到自动补全
    2. 所有类型都是推断出来的,不需要指定是String还是Int
    3. 如果JSON 无效,您将收到详细错误。这确实节省了很多时间
    4. 轻松访问嵌套JSON

    【讨论】:

      【解决方案3】:

      Realm 没有任何内置的键路径/值映射机制,因此您传递给Object(value:) 的任何内容都需要与该模型的架构完全匹配。就像 KVC。

      无论您做什么,都需要在将这些值传递到 Realm 之前进行清理(例如映射键、转换值、折叠/展开对象)。您可以自己通过递归遍历从 JSON 获得的字典/数组来执行此操作,也可以使用类似 ObjectMapper 的库来执行此操作,该库旨在简化此类工作。 Here's one ObjectMapper & Realm 用户同时使用这两种工具的方式。

      值得注意的是,Realm 确实打算在未来最终支持这种键映射(跟踪为 #694),但相关工作尚未开始。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-12-18
        • 2022-01-18
        • 1970-01-01
        • 1970-01-01
        • 2012-03-27
        • 2019-07-05
        • 2019-12-18
        • 1970-01-01
        相关资源
        最近更新 更多