RestKit 在 PUT 请求时抛出 NSInternalInconsistencyException

Posted

技术标签:

【中文标题】RestKit 在 PUT 请求时抛出 NSInternalInconsistencyException【英文标题】:RestKit throws NSInternalInconsistencyException upon PUT request 【发布时间】:2015-05-27 15:52:53 【问题描述】:

当以下列方式发出PUT 请求时,我的应用程序因NSInternalInconsistencyException 而崩溃:

通过HTTP GET下载配置文件信息 更新客户端上的配置文件 通过HTTP PUT上传更改 再次解析PUT响应正文的正文

我得到的错误

2015-05-27 17:27:17.796 XYZ[17093:2526798] *** 由于未捕获的异常“NSInternalInconsistencyException”而终止应用程序,原因:“无法将具有实体“公司”的对象添加到“公司”实体的缓存中''

错误来自这里RKEntityByAttributeCache.m#L333:

 NSAssert([entity isKindOfEntity:self.entity], @"Cannot add object with entity '%@' to cache for entity of '%@'", [entity name], [self.entity name]);

现在奇怪的是,entityself.entity 对象都具有相同的调试描述。所以我不知道这两个实例的NSEnityDescriptor 可能如何变化。

到目前为止我尝试过的事情

从模拟器中删除应用程序:然后我可以更新它一次,然后我再次收到上述错误。 删除NSAssert 语句:PUT 操作现在可以正常工作了。 按照here 的描述禁用缓存(在 Restkit 0.24.1 中,这似乎不再可能)

我的映射

我确实将我的映射实现为RKManagedObjectStore 的扩展,如下所示:

extension RKManagedObjectStore
    var companyMapping: RKEntityMapping
        let mapping = RKEntityMapping(
            forEntityForName: "Company",
            inManagedObjectStore: self
        )
        mapping.addAttributeMappingsFromArray(
            ["id", "name"]
        )
        mapping.identificationAttributes = ["id"]

        return mapping
    

    var profileMapping: RKEntityMapping
        let mapping = RKEntityMapping(
            forEntityForName: "Profile",
            inManagedObjectStore: self
        )
        mapping.addAttributeMappingsFromArray(
            ["id", "content", "language", "profileImageId" ]
        )
        mapping.identificationAttributes = ["id"]
        mapping.addRelationshipMappingWithSourceKeyPath("companies", mapping: companyMapping)

        return mapping
    

我发布到服务器并以相同格式返回响应的数据:


    "content": "XYZ",
    "id": "profile-1",
    "language": "de",
    "companies": [
        "id": "company-1",
        "name": "Somecompany Inc."
    ]

更新NSMangedObectContext

由于该问题似乎与多个NSManagedObjectContexts 有关,因此我设置了 RestKit 和 MOC:

init(baseURL: String, dataModelName: String)

    let modelURL = NSBundle.mainBundle().URLForResource(dataModelName, withExtension: "momd")!
    let managedObjectModel = NSManagedObjectModel(contentsOfURL: modelURL)!
    self.managedObjectStore = RKManagedObjectStore(managedObjectModel: managedObjectModel)

    let storePath = RKApplicationDataDirectory().stringByAppendingPathComponent("\(dataModelName).sqlite")

    var error: NSError? = nil
    managedObjectStore.addSQLitePersistentStoreAtPath(storePath,
        fromSeedDatabaseAtPath: nil,
        withConfiguration: nil,
        options: nil,
        error: &error
    )
    if let e = error
        // Omitted: Delete the SQLite store and re-create it
    
    managedObjectStore.createManagedObjectContexts()
    managedObjectStore.managedObjectCache = RKInMemoryManagedObjectCache(
        managedObjectContext: managedObjectStore.persistentStoreManagedObjectContext
    )
    objectManager = RKObjectManager(baseURL: NSURL(string: baseURL))
    objectManager.managedObjectStore = managedObjectStore
    objectManager.requestSerializationMIMEType = RKMIMETypeJSON;

    super.init(baseURL: baseURL)

    setupMapping()

【问题讨论】:

【参考方案1】:

现在奇怪的是,实体和 self.entity 对象都有相同的调试描述。

实体描述的地址必须不同。

这通常发生在您篡改 RestKit 正在使用的托管对象上下文以便比较的实体来自 2 个不同的上下文并因此不同时,或者当您直接从错误的上下文传递托管对象时。

【讨论】:

你能解释一下地址是什么意思吗?我在NSEntityDescription 中没有找到这个。 指针 - 它们是不同的实例。实体名称的描述相同,但底层上下文不同...... 好的,这听起来很合理,但是现在当我发布我的对象然后解析响应并将其映射回我的原始对象时,我如何确保这两个上下文不会干扰彼此?有什么想法吗? 为什么要使用单独的上下文?您通常应该保持简单并从主要上下文中工作,并允许 RestKit 处理所需的任何其他上下文... 这解决了我的问题,我不小心为每个服务创建了多个上下文,所以我改变了这个并且问题消失了【参考方案2】:

您必须创建一个 ManagedObjectStore。我怀疑self 作为参数是否正确。我从您的解释中推断出 self 是 NSManagedObject 的子类,即您要映射的实体 CompanyProfile 但是您需要一个 RKManagedObjectStore 并将其作为第二个参数传递。

let mapping = RKEntityMapping(
    forEntityForName: "Profile",
    inManagedObjectStore: <pointer to the RKManagedObjectStore>
)

【讨论】:

感谢您的评论。我创建了RKManagedObjectStore 的扩展来实现我的映射,因此 self 指的是实际的对象存储。我会相应地更新我的答案。 我通常扩展实体,但我想这取决于每个人。

以上是关于RestKit 在 PUT 请求时抛出 NSInternalInconsistencyException的主要内容,如果未能解决你的问题,请参考以下文章

使用 RESTkit PUT 请求、更改标头并将响应保存在核心数据中

如何将 PUT 请求添加到 RestKit + Core Data?

使用 POST 方法上传 JSON 对象时抛出错误请求异常

C# HttpClient.SendAsync 在测试某些 URL 时抛出“发送请求时发生错误”异常

GraphQL java:当请求有未使用的变量时抛出异常

当有任何 SOAP 请求的挂起的实体框架数据库迁移时抛出 SOAP 异常