Par*_*ots 6 core-data objective-c nsmanagedobject ios restkit
我正在使用RestKit从我的RoR服务中获取对象,并使用CoreData来保留一些对象(更多的静态类型查找表对象).TasteTag是其中一个持久对象:
#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 ..
Run Code Online (Sandbox Code Playgroud)
我有从RoR服务器返回的数据,它按预期映射到对象.在RestKit获取请求后,Core Data实体似乎也正常映射:
"<TasteTag: 0x6e87170> (entity: TasteTag; id: 0x6e85d60 <x-coredata://03E4A20A-21F2-4A2D-92B4-C4424893D559/TasteTag/p5> ; data: <fault>)"
Run Code Online (Sandbox Code Playgroud)
问题是当我尝试访问对象的属性时,故障似乎无法解决.起初我只是调用属性,这些属性总是以零形式返回(即使它应该触发错误):
for (TasteTag *tag in self.vintage.tasteTags) {
[tagNames addObject:tag.name]; //get error of trying to add nil to array
}
Run Code Online (Sandbox Code Playgroud)
在查看手动触发故障后(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>''
Run Code Online (Sandbox Code Playgroud)
在.sqlite中查找基于键的实体(TasteTag/p5)确实显示它映射到我期望的那个.
与RestKit相关的其他帖子建议禁用对象缓存(我没有使用),因为这通常是由实体被删除引起的.但是在这个阶段我只是阅读而不是删除,而且我没有缓存.
如果我只是打电话,[TasteTag allObjects]我能够让所有对象恢复正常,并且它们可以毫无问题地加载.它只是出现故障的情况.
Rya*_*sal 10
我找到了一个适合我的解决方案(我不确定它对你的情况有多适用,但是我将它添加为答案,因为它为我解决了这个(或非常类似的)问题):
几天前,我运行了这个RKTwitterCoreData例子并注意到它在我的工作中非常完美,此时代码非常简单并做了几乎相同的事情,但事实并非如此.我遇到了许多未实现的错误.所以我决定修改我处理的所有代码,RestKit以反映RKTwitterCoreData示例的作用.
我会把它分成几块,试着帮助你按照我当时的思路(因为我不认为我们的问题是相同的).
我最初的实施假设
由于RestKit可以将对象备份到Core Data,因此我假设这些托管对象可以互换使用.例如,我可以使用Core Data中的对象,其方式与从远程Web服务检索的对象完全相同.我甚至可以将它们合并在一起以获取所有数据.
我错了
我注意到这个RKTwitterCoreData代码至少没有以这种方式流动.我的代码中有一大块与他们的代码匹配,但最大的区别在于他们没有将这些对象视为可互换的.实际上,他们从未使用过从远程数据存储中获取的对象.相反,他们只是让它"陷入困境".我只能假设这意味着它们被添加到Core Data的数据存储中,因为它适用于它们,现在,对我而言.
细节
我的应用程序在修改我的代码以使用此流程后工作.我只能猜测我们看到的无法填充的错误与使用我们从Web服务返回的Core Data支持的对象有关.如果您只是忽略它们然后进行提取,您将获得所有内容(包括最近的请求),并且您不应该得到任何无法填充的错误.
详细说来,如果你看一下,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]];
}];
}
Run Code Online (Sandbox Code Playgroud)
一切看起来都很正常(至少与我最初的加载方式相比).但是看看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];
}
Run Code Online (Sandbox Code Playgroud)
样品甚至没有碰到objects参数!(除了NSLog当然...)
结论/ TL;博士
不要使用您重新访问的托管对象,objectLoader:didLoadObjects:就好像它们完全由Core Data支持一样.相反,忽略它们并从Core Data重新获取.所有对象,包括上次请求中的对象都在那里.否则,你将得到无法弥补的错误(至少我做过).
根据 Ryan 的建议记录我的修复(阅读:hack)。
错误似乎在于 RestKit 如何假设您将使用从其objectLoader:didLoadObjects:方法返回的对象。他们似乎假设它将全部由核心数据支持(并遵循与 Ryan 谈论的类似的流程 - 让它同步到核心数据,然后重新查询),或者您将使用所有非核心数据支持的对象,并且只是保留这些结果。
就我而言,我有一个混合 - 非核心数据支持的对象的根数组,每个对象都包含一组核心数据支持的实体。顶级对象是我不介意查询服务器的对象,并且没有理由在它们显示的视图之外本地保留。似乎一旦objectLoader:didLoadObjects:完成,支持参数内核心数据实体的托管对象上下文objects就是处理掉(假设您将重新查询它们),导致将来对实体的任何调用都会被视为错误,即使您无法触发错误并加载数据(结果在 中NSObjectInaccessibleException)。
我用一个丑陋的黑客解决了这个问题 - 在objectLoader:didLoadObjects:我访问核心数据实体的托管对象上下文之一并将其复制到视图(self.context = [tag managedObjectContext];)内的属性中。这可以防止上下文在objectLoader:didLoadObjects:完成后被释放,从而允许我稍后在视图中访问实体而不会出现问题。
另一种解决方案是使用新上下文手动重新查询每个实体并将其复制回存储的返回对象。当人们去显示它们时,或者可能objectLoader:didLoadObjects:使用新的上下文进行一些后处理时,可以这样做。实体 ID 仍然存在于故障对象上,因此即使在原始 RestKit 上下文消失后,也可以使用它来重新查询,而不会出现问题。但必须像这样重新查询对象图中的每个实体似乎很愚蠢。
| 归档时间: |
|
| 查看次数: |
2970 次 |
| 最近记录: |