【问题标题】:RestKit dynamic mapping with nested items带有嵌套项的 RestKit 动态映射
【发布时间】:2016-09-13 21:37:49
【问题描述】:

我在为一组结果配置动态映射时遇到问题。我想要映射的结果对象嵌入在描述封闭对象类型的“容器”中。

我有类似于以下的 JSON:

"list": {
    "name": ""
    "item_infos": [
    {
        "type": "TaskItem",
        "item": {
            "id": 0
            "title": "A Task Item",
            "task": "..."
        }
        "url": "..."
    },
    {
        "type": "ReminderItem",
        "item": {
            "id": 0
            "title": "A Reminder Item",
            "reminder": "..."
        }
        "url": "..."
    }]
}


我想将其映射为具有Items 数组的List 对象,其中每个项目可能属于不同类型。不同的types 是有限且已知的。

class List: NSManagedObject {
    @NSManaged var name: String
    @NSManaged var items: NSOrderedSet
}

class Item: NSManagedObject {
    @NSManaged var identifier: Int32
    @NSManaged var title: String

    // Each mappable `Item` is responsible for providing its own
    // mapping object. It's overridden in the subclasses below.
    class func responseMappingForManagedObjectStore(dos: RKManagedObjectStore) -> RKEntityMapping { ... }
}

class TaskItem: Item {
    @NSManaged var task: String
}

class ReminderItem: Item {
    @NSManaged var reminder: String
}


如何使用RKDynamicMapping 直接在列表下映射嵌入的item,同时仍然使用type 字段?我正在尝试按照这些方式进行响应映射:

let listMapping = RKEntityMapping(forEntityForName: "List", inManagedObjectStore: store)
responseMapping.addAttributeMappingsFromDictionary(["name": "title"])

let dynamicItemMapping = RKDynamicMapping()
dynamicItemMapping.setObjectMappingForRepresentationBlock { representation in

    let itemMapping: RKEntityMapping

    switch representation.valueForKeyPath("type") as? String {
    case .Some("TaskItem"):     itemMapping = TaskItem.responseMappingForManagedObjectStore(objectStore)
    case .Some("ReminderItem"): itemMapping = ReminderItem.responseMappingForManagedObjectStore(objectStore)
    default:                    return nil

    // This is the bit I'm failing to solve. How can I return a mapping
    // that essentially "skips" a level of the JSON, and just maps the
    // embedded `item`, not the `item_info`.
    let itemInfoMapping = RKObjectMapping(forClass: NSMutableDictionary.self)
    itemInfoMapping.addRelationshipMappingWithSourceKeyPath("item", mapping: itemMapping)
    return itemInfoMapping
}

listMapping.addPropertyMapping(RKRelationshipMapping(
    fromKeyPath: "item_infos",
    toKeyPath:   "items",
    withMapping: dynamicItemMapping))

使用此映射,会引发异常:

-[__NSDictionaryM _isKindOfEntity:]: unrecognized selector sent to instance 0x7fd2603cb400

这并不让我感到惊讶,因为动态映射的设置方式无论如何都感觉不对 - 我正在寻找一种方法来“跳过” JSON 的一个级别并且只映射嵌入的 @987654331 @。


另一种尝试是将fromKeyPath 完全指定为"item_infos.item"listMapping 的关系,但是我不能使用动态映射块中的type 字段来确定要使用的Item 映射的类型:

// ...
dynamicItemMapping.setObjectMappingForRepresentationBlock { representation in
    // `type` inaccessible from the nested item representation
    switch representation.valueForKeyPath("type") as? String {
    case .Some("TaskItem"):     return TaskItem.responseMappingForManagedObjectStore(objectStore)
    case .Some("ReminderItem"): return ReminderItem.responseMappingForManagedObjectStore(objectStore)
    default:                    return nil
}

listMapping.addPropertyMapping(RKRelationshipMapping(
    fromKeyPath: "item_infos.item",
    toKeyPath:   "items",
    withMapping: dynamicItemMapping))

【问题讨论】:

  • 你还没有说问题出在哪里。我个人不会有多个不同的实体,我会有 1 个带有类型标识符的实体。
  • @Wain 抱歉,我没有把问题说得很清楚。我已经更新了这个问题,但简而言之,我给出的映射示例不起作用——第一个引发异常,第二个尝试基于无法从动态映射块中的字典(由于关系映射的fromKeyPath 级别太深)。为了问题的清晰/简洁起见,简化了实体;实际上,对象的不同足以保证它们是独立的实体。

标签: ios dynamic nested mapping restkit


【解决方案1】:

您不能完全按照您的意愿去做,因为您将核心数据关系连接到将包含托管对象的字典数组。

最简单的解决方案是通过在源键(路径)的开头添加item.,将您的跳过逻辑从其所在位置取出并创建托管对象(任务和提醒)的所有映射。所以

"item.title" : "title"

【讨论】:

  • 谢谢,知道我走的是一条行不通的路,这对我很有帮助。我想我以某种方式希望字典可以充当中间表示,允许将项目映射到核心数据中。我还希望避免更改单个项目映射,因为它们很好地被对象类封装,并且还有其他路由可以在没有item 前缀的情况下使用这些映射。我想我会克服它并在返回映射的方法中添加一个sourceKeyPathPrefix 参数。再次感谢您的帮助!
  • 只有当列表映射与核心数据无关时,字典方法才有效,因为它是/是关系不适用于中间,因为它在核心中的非核心数据-日期关系(希望有意义)
  • 是的,这是有道理的。感谢您的帮助,我知道现在最好的方法了。
  • 嗨,@Wain!没有完全明白,但这是否意味着如果我的项目中没有 CoreData,我可以以“更干净”的方式解决这个问题(与使用中间人“item”键为所有属性添加前缀相比)?你知道这方面的任何例子吗?我有几乎相同的问题,但想使用现有的通用映射并减少复制粘贴的代码。谢谢!
  • @slxl 答案并不特定于核心数据,答案更多地涉及如何将源 JSON 结构变异为稍微不同的模型结构
猜你喜欢
  • 1970-01-01
  • 2013-02-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-05-28
相关资源
最近更新 更多