手动映射 JSON 对象时,RestKit 关系未映射

Posted

技术标签:

【中文标题】手动映射 JSON 对象时,RestKit 关系未映射【英文标题】:RestKit relationships not mapping when manually mapping JSON object 【发布时间】:2015-03-30 19:28:36 【问题描述】:

我正在关注一些关于如何使用 RKMapperOperation 直接映射传入 JSON 数据的建议帖子。我的实体对象正在数据存储中创建,但没有正确的关系。有趣的是,如果我在已经映射传入的 JSON(通过 websockets)之后直接使用 Core Data 方法创建一个对象,那么该操作似乎会“充实”我在不正确实体中的关系。

总结顺序:

    JSON 数据通过 websocket 连接进入应用程序 我使用下面的代码映射它,但没有映射关系 我使用带有 Core Data 的本地创建(不是 RestKit)对象将其他一些记录保存在同一实体中。 我的从 JSON 映射的对象现在附加了它的关系!

这是 JSON 数据:


    "checkin": 
        "session_id": 1,
        "attendee_id": 70,
        "source": "list",
        "created_at": "2015-03-26 11:53:08",
        "cache_id": "9234d700852df5c7402b87adf6ecfc19",
        "checkout": "0",
        "updated_at": "2015-03-27 03:53:09",
        "id": 359
    

这是我的映射函数

func mapEntityFromJson(JSONString: String, key: String, mapping: RKEntityMapping!) -> NSManagedObject? 
    let MIMEType = "application/json"
    var error: NSError? = nil
    let data = JSONString.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)
    let jsonDictionary: NSDictionary = NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.MutableContainers, error: &error) as NSDictionary
    let parsedData: AnyObject! = RKMIMETypeSerialization.objectFromData(data, MIMEType: MIMEType, error: &error)
    if (parsedData == nil && error != nil) 
        // Parser error...
        return nil
    

    let mappingsDictionary = [ key: mapping ]

    let mappingDS = RKManagedObjectMappingOperationDataSource(managedObjectContext: self.objectStore.persistentStoreManagedObjectContext, cache: self.objectStore.managedObjectCache)

    let mapper = RKMapperOperation(representation: parsedData, mappingsDictionary: mappingsDictionary)
    mapper.mappingOperationDataSource = mappingDS
    var mappingError: NSError? = nil
    let isMapped = mapper.execute(&mappingError)
    if (isMapped && mappingError == nil) 
        // Trying to save twice per some other example
        self.objectStore.persistentStoreManagedObjectContext.save(&error)
        self.objectStore.persistentStoreManagedObjectContext.saveToPersistentStore(&error)
        let result = mapper.mappingResult.firstObject() as NSManagedObject
                    return result
    
    return nil

这是我传递给这个函数的关系映射:

func checkinMapping() -> RKEntityMapping 
    let checkinMapping = RKEntityMapping(forEntityForName: "Checkin", inManagedObjectStore: objectStore)
    let checkinDictionary = ["source": "source", "checkout": "checkout", "cache_id": "cacheId", "attendee_id": "attendeeId", "session_id": "sessionId"]

    checkinMapping.addAttributeMappingsFromDictionary(baseRecordDictionary)
    checkinMapping.addAttributeMappingsFromDictionary(checkinDictionary)
    checkinMapping.addConnectionForRelationship("attendee", connectedBy: ["attendeeId": "id"])
    checkinMapping.addConnectionForRelationship("session", connectedBy: ["sessionId": "id"])
    checkinMapping.identificationAttributes = ["cacheId"]
    checkinMapping.setDefaultValueForMissingAttributes = true

    return checkinMapping

以下是通知 websocket 订阅时函数的调用方式:

let jsonString = "<the JSON data per above>"
let mappingResult = self.mapEntityFromJson(jsonString, key: "checkin", mapping: self.checkinMapping())

attendee_idsession_id 值应该与AttendeeSession 实体建立关系,但是当我查看Core Data 底层的sqlite 数据时,即使传入attendeeId,关系列也是空白的和 sessionId 字段被映射。一旦我在本地进行另一个保存,那么这些关系列就会被映射。

有什么想法吗?

编辑: 我应该补充一点,当从完整的 RestKit 调用(如 .getObject 或作为 .postObject 的结果)映射签入时,映射将毫无问题地工作。只是在我这里的手动映射中,它似乎分崩离析。

【问题讨论】:

显示 JSON。您使用操作而不是对象管理器是否有原因?该问题也没有显示您显示的两段代码之间的链接...... 我已经用 JSON 数据以及如何使用函数调用扩展了这个问题。 所以看起来你的问题真的是你想要创建存根对象,如果对象不存在,那么你可以连接关系,然后稍后填写详细信息? 其实attendee_id和session_id分别引用的attendee对象和session对象在签到之前就一直存在。在对象通过 Web 套接字进入之前,这些记录始终存在。无论如何,我将探索以 JSON 格式发送它们,但考虑到我已经在本地拥有记录,这将使通过的数据大小增加一倍以上,这似乎效率低下。 如果您已经拥有它们,则无需将它们嵌套发送。您确定在运行此部分之前它们已保存到磁盘吗? 【参考方案1】:

这是最终的解决方案,它涉及到来自@wain 的大量帮助以及另一篇文章中关于需要使 operationQueue 等到所有操作完成或映射过程尚未完成映射关系的关键点。所以我的 NSManagedObject 返回时没有连接任何关系。用于正确并发和保存数据的私有子上下文的组合以及等待问题解决了该问题。这是最终的映射代码:

func mapEntityFromJson(JSONString: String, key: String, mapping: RKEntityMapping!) -> NSManagedObject? 
    let MIMEType = "application/json"
    var error: NSError? = nil
    let data = JSONString.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)
    let jsonDictionary: NSDictionary = NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.MutableContainers, error: &error) as NSDictionary
    let parsedData: AnyObject! = RKMIMETypeSerialization.objectFromData(data, MIMEType: MIMEType, error: &error)
    if (parsedData == nil && error != nil) 
        // Parser error...
        return nil
    

    let mapperContext = self.objectStore.newChildManagedObjectContextWithConcurrencyType(NSManagedObjectContextConcurrencyType.PrivateQueueConcurrencyType, tracksChanges: true)

    let mappingsDictionary = [ key: mapping ]

    let mappingDS = RKManagedObjectMappingOperationDataSource(managedObjectContext: mapperContext, cache: self.objectStore.managedObjectCache)
    var mappingResult: RKMappingResult? = nil
    var result: NSManagedObject? = nil

    let mapper = RKMapperOperation(representation: parsedData, mappingsDictionary: mappingsDictionary)
    mappingDS.operationQueue = self.operationQueue
    mappingDS.parentOperation = mapper
    mapper.mappingOperationDataSource = mappingDS
    var mappingError: NSError? = nil
    let isMapped = mapper.execute(&mappingError)
    // Necessary to wait for relationships to map.
    if self.operationQueue!.operationCount > 0 
        self.operationQueue!.waitUntilAllOperationsAreFinished()
    
    if (isMapped && mappingError == nil) 
        mapperContext.saveToPersistentStore(&error)
        mappingResult = mapper.mappingResult
    

    if mappingResult != nil 
        result = mappingResult!.firstObject() as? NSManagedObject
    

    return result

目前我们将其保留在内存缓存中,并且看不到其他人报告的重复问题。

【讨论】:

以上是关于手动映射 JSON 对象时,RestKit 关系未映射的主要内容,如果未能解决你的问题,请参考以下文章

Restkit 0.20 对象在获取 json 响应后未映射

使用 RESTKIT 0.20 映射未命名值的 JSON 数组

Restkit 映射 - 使用嵌入式对象/关系作为标识属性

RestKit .22:无法成功映射与嵌套 JSON 的关系

RestKit 对象映射:如何从键值映射到新对象/关系?

在 Restkit 中映射单个 JSON 对象时出错