2012-01-12 89 views
6

我使用RestKit从我的RoR服务中抓取对象并使用CoreData来保存一些对象(更多静态类型的查找表对象)。 TasteTag是那些持久对象之一:Restkit加载的嵌套核心数据实体导致NSObjectInaccessibleException

#ifdef RESTKIT_GENERATE_SEED_DB 
    NSString *seedDatabaseName = nil; 
    NSString *databaseName = RKDefaultSeedDatabaseFileName; 
#else 
    NSString *seedDatabaseName = RKDefaultSeedDatabaseFileName; 
    NSString *databaseName = @"Model.sqlite"; 
#endif 

RKObjectManager* manager = [RKObjectManager objectManagerWithBaseURL:kServerURL]; 
manager.objectStore = [RKManagedObjectStore objectStoreWithStoreFilename:databaseName usingSeedDatabaseName:seedDatabaseName managedObjectModel:nil delegate:self]; 

.. lots of fun object mapping .. 

RKManagedObjectMapping* tasteTagMapping = [RKManagedObjectMapping mappingForClass:[TasteTag class]]; 
[tasteTagMapping mapKeyPath:@"id" toAttribute:@"tasteTagID"]; 
[tasteTagMapping mapKeyPath:@"name" toAttribute:@"name"]; 
tasteTagMapping.primaryKeyAttribute = @"tasteTagID"; 
[[RKObjectManager sharedManager].mappingProvider setMapping:tasteTagMapping forKeyPath:@"taste_tags"]; 
[[RKObjectManager sharedManager].mappingProvider addObjectMapping:tasteTagMapping]; 

.. some more mapping .. 

我从RoR的服务器回来的数据,并预期它变得映射为对象。

"<TasteTag: 0x6e87170> (entity: TasteTag; id: 0x6e85d60 <x-coredata://03E4A20A-21F2-4A2D-92B4-C4424893D559/TasteTag/p5> ; data: <fault>)" 

的问题是,当我试图对故障不能似乎是火的对象访问属性:核心数据实体RestKit收到请求后背部也似乎映射的罚款。起初我只是打电话的特性,它总是回来为无(尽管这应该火故障):

for (TasteTag *tag in self.vintage.tasteTags) { 
    [tagNames addObject:tag.name]; //get error of trying to add nil to array 
} 

寻找到手动触发故障(http://www.mlsite.net/blog/?p=518)我打过电话[tag willAccessValueForKey:nil]导致后:

Terminating app due to uncaught exception 'NSObjectInaccessibleException', reason: 'CoreData could not fulfill a fault for '0x6e7b060 <x-coredata://03E4A20A-21F2-4A2D-92B4-C4424893D559/TasteTag/p5>'' 

根据关键字(TasteTag/p5)查找.sqlite中的实体确实将它映射到我期望的那个。

与RestKit相关的其他职位建议禁用对象缓存(我没有使用),因为这通常是由一个实体被删除引起的。但在这个阶段,我只是在阅读,而不是删除,而且我没有缓存。

如果我只是打电话[TasteTag allObjects]我能够得到所有的对象回来罚款,他们加载没有问题。只是在他们似乎错误的情况下。

+0

希望你找到解决方案,我遇到了几乎相同的问题。 – 2012-01-13 07:14:26

+0

@ryan如果你发现任何东西让我知道,到目前为止我没有运气 – Parrots 2012-01-13 19:54:43

+0

@ryan - 看起来像它可能不是RestKit特定的。后续问题在这里:http://stackoverflow.com/questions/8856867/copying-objects-with-core-data-objects-in-them – Parrots 2012-01-13 20:38:46

回答

4

根据Ryan的建议记录我的修复(阅读:hack)。

该错误似乎是在RestKit假定您将使用从objectLoader:didLoadObjects:方法返回的对象的方式。他们似乎认为它将全部由Core Data支持(并且遵循类似于Ryan所谈论的流程 - 让它与Core Data同步,然后重新查询),或者您将使用所有非Core Data支持的对象,并且只是保持这些结果。

在我的情况下,我有一个混合 - 非核心数据支持对象的根数组,每个对象都包含一个Core Data支持的实体数组。顶级对象是我不介意查询服务器的对象,没有理由在本地持久保存它们显示的视图。似乎一旦objectLoader:didLoadObjects:完成支持objects内核心数据实体的托管对象上下文param被处置(假设你将重新查询它们),导致任何未来的实体调用都会导致被视为错误,即使你不能触发错误并加载数据(结果为NSObjectInaccessibleException)。

我用一个丑陋的黑客绕过它 - 在objectLoader:didLoadObjects:我访问核心数据实体的管理对象上下文之一,并将其​​复制到视图内的属性(self.context = [tag managedObjectContext];)。这可以防止objectLoader:didLoadObjects:完成后发布的上下文,从而允许我在稍后的视图中访问实体,而不会出现问题。

另一种解决方案是使用新的上下文为每个实体手动重新查询并将其复制回存储的返回对象。人们可以通过使用新的上下文来显示它们,或者在objectLoader:didLoadObjects:中进行一些后处理。实体ID仍然存在于故障对象中,因此即使在原始RestKit上下文消失之后,也可以使用它重新查询而不会出现问题。但是像这样重新查询对象图中的每个实体似乎很愚蠢。

+0

您可以关闭自动同步,并在需要时手动将对象存储在CD模型中。但我需要一些文档!不管怎么说,还是要谢谢你 :) – 2012-07-16 11:45:55

10

我发现了一个适用于我的解决方案(我不确定它是如何适用于您的情况,但我将它添加为答案,因为它解决了我(或非常相似)的问题):

几天前,我运行了RKTwitterCoreData示例,并注意到它的工作完美,而我的代码非常简单,而且几乎完成同样的事情,但没有。我得到了很多未完成的故障。所以我决定修改处理RestKit的所有代码,以反映RKTwitterCoreData示例如何实现它。

我会把它分成几块,试图帮助你按照我当时的思路(因为我不认为我们的问题是相同的)。

我原来实行假设

由于RestKit可以备份对象,以核心数据,我认为这些管理对象可以互换使用。例如,我可以像使用从远程Web服务检索到的那样,使用Core Data中的对象。我甚至可以将它们合并在一起以获取所有数据。

我错了

我注意到RKTwitterCoreData的代码没有流量这种方式在最少。我的代码中有相当一部分与他们的代码相匹配,但最大的区别是他们没有将这些对象视为可互换的。实际上,他们从未使用过他们从远程数据存储获得的对象。相反,他们只是让这个“通过裂缝”。我只能假设这意味着它们被添加到Core Data的数据存储中,因为它适用于他们,现在也适用于我。

详细

我的应用程序修改我的代码利用这一流程后工作。我只能推测,我们看到的无法实现的错误与使用核心数据支持的对象有关,我们从web服务获取。如果你只是忽略这些,然后做一个抓取,你会得到一切(包括最近的请求),你不应该得到任何无法补救的错误。

具体地说就是,如果你看一下RKTwitterViewController你会发现,行对象的45-61手柄装:

- (void)loadObjectsFromDataStore { 
    [_statuses release]; 
    NSFetchRequest* request = [RKTStatus fetchRequest]; 
    NSSortDescriptor* descriptor = [NSSortDescriptor sortDescriptorWithKey:@"createdAt" ascending:NO]; 
    [request setSortDescriptors:[NSArray arrayWithObject:descriptor]]; 
    _statuses = [[RKTStatus objectsWithFetchRequest:request] retain]; 
} 

- (void)loadData { 
    // Load the object model via RestKit  
    RKObjectManager* objectManager = [RKObjectManager sharedManager]; 
    [objectManager loadObjectsAtResourcePath:@"/status/user_timeline/RestKit" delegate:self block:^(RKObjectLoader* loader) { 
     // Twitter returns statuses as a naked array in JSON, so we instruct the loader 
     // to user the appropriate object mapping 
     loader.objectMapping = [objectManager.mappingProvider objectMappingForClass:[RKTStatus class]]; 
    }]; 
} 

看起来一切正常(至少比我是如何开始做这个加载)。但是看看在objectLoader:didLoadObjects:委托方法:

- (void)objectLoader:(RKObjectLoader*)objectLoader didLoadObjects:(NSArray*)objects { 
    [[NSUserDefaults standardUserDefaults] setObject:[NSDate date] forKey:@"LastUpdatedAt"]; 
    [[NSUserDefaults standardUserDefaults] synchronize]; 
    NSLog(@"Loaded statuses: %@", objects); 
    [self loadObjectsFromDataStore]; 
    [_tableView reloadData]; 
} 

样品甚至没有触及objects参数! (除了当然的NSLog ...)

结论/ TL;博士

不要使用管理的对象你在后面objectLoader:didLoadObjects:好像他们完全由核心数据支持。相反,忽略它们并从Core Data重新获取。所有对象,包括最后一次请求中的对象都在那里。否则,你会得到无法补救的错误(至少我是)。

+0

我在调试过程中得出了同样的结论。他们似乎认为你会让它同步到CD然后重新查询。我遇到的问题是我没有计划将所有的对象都备份到CD上(不必考虑将它们存储以备后用 - 只是这一个视图呈现)。这迫使我使用返回的对象。 我最终通过在viewController中保留NSManagedObject的managedContext来修复(阅读:以丑陋的方式进行黑客攻击)。这样做可以让我访问cellForIndexPath中的对象。 – Parrots 2012-01-16 15:52:31

+0

您可能值得您的时间来补充,作为任何其他不幸的旅客RestKit这方面的答案。我对这个图书馆印象深刻,但是我觉得这个警告没有更好的文档记录。 – 2012-01-16 16:06:06

+0

同意文件。我真的可以使用一些最新的文档而不是较旧的文档。感谢这里的见解。 – 2012-07-16 11:43:18

相关问题