2012-11-06 95 views
4

我的应用程序在后台线程中进行更新,然后保存上下文更改。 在主要情况下,有一个表格视图,与NSFetchedResultsController一起使用。 对于一段时间更新正常工作,但然后引发异常。 要检查这个我已经添加NSLog(@"%@", [self.controller fetchedObjects]);-controllerDidChangeContent:。 这里是我的了:CoreData更新问题

"<PRBattle: 0x6d30530> (entity: PRBattle; id: 0x6d319d0 <x-coredata://882BD521-90CD-4682-B19A-000A4976E471/PRBattle/p2> ; data: {\n battleId = \"-1\";\n finishedAt = \"2012-11-06 11:37:36 +0000\";\n opponent = \"0x6d2f730 <x-coredata://882BD521-90CD-4682-B19A-000A4976E471/PROpponent/p1>\";\n opponentScore = nil;\n score = nil;\n status = 4;\n})", 
"<PRBattle: 0x6d306f0> (entity: PRBattle; id: 0x6d319f0 <x-coredata://882BD521-90CD-4682-B19A-000A4976E471/PRBattle/p1> ; data: {\n battleId = \"-1\";\n finishedAt = \"2012-11-06 11:37:36 +0000\";\n opponent = \"0x6d2ddb0 <x-coredata://882BD521-90CD-4682-B19A-000A4976E471/PROpponent/p3>\";\n opponentScore = nil;\n score = nil;\n status = 4;\n})", 
"<PRBattle: 0x6d30830> (entity: PRBattle; id: 0x6d31650 <x-coredata://882BD521-90CD-4682-B19A-000A4976E471/PRBattle/p11> ; data: <fault>)", 
"<PRBattle: 0x6d306b0> (entity: PRBattle; id: 0x6d319e0 <x-coredata://882BD521-90CD-4682-B19A-000A4976E471/PRBattle/p5> ; data: {\n battleId = 325;\n finishedAt = nil;\n opponent = \"0x6d2f730 <x-coredata://882BD521-90CD-4682-B19A-000A4976E471/PROpponent/p1>\";\n opponentScore = 91;\n score = 59;\n status = 3;\n})", 
"<PRBattle: 0x6d30730> (entity: PRBattle; id: 0x6d31a00 <x-coredata://882BD521-90CD-4682-B19A-000A4976E471/PRBattle/p6> ; data: {\n battleId = 323;\n finishedAt = nil;\n opponent = \"0x6d2ddb0 <x-coredata://882BD521-90CD-4682-B19A-000A4976E471/PROpponent/p3>\";\n opponentScore = 0;\n score = 0;\n status = 3;\n})", 
"<PRBattle: 0x6d307b0> (entity: PRBattle; id: 0x6d31630 <x-coredata://882BD521-90CD-4682-B19A-000A4976E471/PRBattle/p9> ; data: {\n battleId = 370;\n finishedAt = \"2012-11-06 14:24:14 +0000\";\n opponent = \"0x79a8e90 <x-coredata://882BD521-90CD-4682-B19A-000A4976E471/PROpponent/p2>\";\n opponentScore = 180;\n score = 180;\n status = 4;\n})", 
"<PRBattle: 0x6d307f0> (entity: PRBattle; id: 0x6d31640 <x-coredata://882BD521-90CD-4682-B19A-000A4976E471/PRBattle/p10> ; data: {\n battleId = 309;\n finishedAt = \"2012-11-02 01:19:27 +0000\";\n opponent = \"0x79a8e90 <x-coredata://882BD521-90CD-4682-B19A-000A4976E471/PROpponent/p2>\";\n opponentScore = 120;\n score = 240;\n status = 4;\n})", 
"<PRBattle: 0x6d30770> (entity: PRBattle; id: 0x6d31620 <x-coredata://882BD521-90CD-4682-B19A-000A4976E471/PRBattle/p7> ; data: {\n battleId = 315;\n finishedAt = \"2012-11-02 02:26:24 +0000\";\n opponent = \"0x79a8e90 <x-coredata://882BD521-90CD-4682-B19A-000A4976E471/PROpponent/p2>\";\n opponentScore = 119;\n score = 179;\n status = 4;\n})" 

断陷对象(0xe972610)这里导致崩溃。在保存之前,我在更新&期间记录了数据。该对象仅在updatedObjects中。为什么这个方法返回“坏”对象? (此外,在更新期间,这个对象几乎每次更新都会受到影响,并且只有在某些通行证变成“坏”之后)。

P.S .:我使用RestKit来管理CoreData。

UPDATE2:

貌似问题是在[self.controller fetchedObjects]枚举。它从- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller调用,似乎这些对象即使在此方法调用期间被修改(我的意思是CoreData更新没有完成到那一点)。可能吗?

更新:

唯一的例外是得到了,当我做了不便。像这样:

for (PRBattle *battle in [self.controller fetchedObjects) { 
    switch (battle.statusScalar) { 
     case ... 
     default: 
      [battle willAccessValueForKey:nil]; 
      NSAssert1(NO, @"Unexpected battle status found: %@", battle); 
    } 
} 

例外是符合-willAccessValueForKey:。战斗的标量状态是枚举,即绑定到整数值1..4。我已经提到了交换机的所有可能的值(在default:之上)。最后一个有break;。因此,只有当battle.statusScalar返回非枚举值时,才有可能。在PRBattle

状态标实施:

- (PRBattleStatuses)statusScalar 
{ 
    [self willAccessValueForKey:@"statusScalar"]; 
    PRBattleStatuses result = (PRBattleStatuses)[self.status integerValue]; 
    [self didAccessValueForKey:@"statusScalar"]; 
    return result; 
} 

而且battle.status有验证规则: - 最小值:1 - 最高值:4 - 默认:没有值

而最后东西 - 调试日志:

objc[4664]: EXCEPTIONS: throwing 0x7d33f80 (object 0xe67d2a0, a _NSCoreDataException) 
objc[4664]: EXCEPTIONS: searching through frame [ip=0x97b401 sp=0xbfffd9b0] for exception 0x7d33f60 
objc[4664]: EXCEPTIONS: catch(id) 
objc[4664]: EXCEPTIONS: unwinding through frame [ip=0x97b401 sp=0xbfffd9b0] for exception 0x7d33f60 
objc[4664]: EXCEPTIONS: handling exception 0x7d33f60 at 0x97b79f 
objc[4664]: EXCEPTIONS: rethrowing current exception 
objc[4664]: EXCEPTIONS: searching through frame [ip=0x97b911 sp=0xbfffd9b0] for exception 0x7d33f60 
objc[4664]: EXCEPTIONS: searching through frame [ip=0x9ac8b7 sp=0xbfffdc20] for exception 0x7d33f60 
objc[4664]: EXCEPTIONS: searching through frame [ip=0x97ee80 sp=0xbfffdc40] for exception 0x7d33f60 
objc[4664]: EXCEPTIONS: searching through frame [ip=0x361d0 sp=0xbfffdc70] for exception 0x7d33f60 
objc[4664]: EXCEPTIONS: searching through frame [ip=0xa701d8 sp=0xbfffde10] for exception 0x7d33f60 
objc[4664]: EXCEPTIONS: catch(id) 
objc[4664]: EXCEPTIONS: unwinding through frame [ip=0x97b911 sp=0xbfffd9b0] for exception 0x7d33f60 
objc[4664]: EXCEPTIONS: finishing handler 
objc[4664]: EXCEPTIONS: searching through frame [ip=0x97b963 sp=0xbfffd9b0] for exception 0x7d33f60 
objc[4664]: EXCEPTIONS: searching through frame [ip=0x9ac8b7 sp=0xbfffdc20] for exception 0x7d33f60 
objc[4664]: EXCEPTIONS: searching through frame [ip=0x97ee80 sp=0xbfffdc40] for exception 0x7d33f60 
objc[4664]: EXCEPTIONS: searching through frame [ip=0x361d0 sp=0xbfffdc70] for exception 0x7d33f60 
objc[4664]: EXCEPTIONS: searching through frame [ip=0xa701d8 sp=0xbfffde10] for exception 0x7d33f60 
objc[4664]: EXCEPTIONS: catch(id) 
objc[4664]: EXCEPTIONS: unwinding through frame [ip=0x97b963 sp=0xbfffd9b0] for exception 0x7d33f60 
objc[4664]: EXCEPTIONS: unwinding through frame [ip=0x9ac8b7 sp=0xbfffdc20] for exception 0x7d33f60 
objc[4664]: EXCEPTIONS: unwinding through frame [ip=0x97ee80 sp=0xbfffdc40] for exception 0x7d33f60 
objc[4664]: EXCEPTIONS: unwinding through frame [ip=0x361d0 sp=0xbfffdc70] for exception 0x7d33f60 
objc[4664]: EXCEPTIONS: unwinding through frame [ip=0x3656f sp=0xbfffdc70] for exception 0x7d33f60 
objc[4664]: EXCEPTIONS: unwinding through frame [ip=0xa701d8 sp=0xbfffde10] for exception 0x7d33f60 
objc[4664]: EXCEPTIONS: handling exception 0x7d33f60 at 0xa701f5 
2012-11-07 13:37:55.463 TestApp[4664:fb03] CoreData: error: Serious application error. An exception was caught from the delegate of NSFetchedResultsController during a call to -controllerDidChangeContent:. CoreData could not fulfill a fault for '0x6d31650 <x-coredata://882BD521-90CD-4682-B19A-000A4976E471/PRBattle/p10>' with userInfo { 
    NSAffectedObjectsErrorKey =  (
     "<PRBattle: 0x6d30830> (entity: PRBattle; id: 0x6d31650 <x-coredata://882BD521-90CD-4682-B19A-000A4976E471/PRBattle/p10> ; data: <fault>)" 
    ); 
} 
+1

你对每个线程使用不同的NSManagedObjectContext吗?看看这个链接接受的答案http://stackoverflow.com/questions/2138252/core-data-multi-thread-application – LombaX

+1

此外,为什么你说对象0xe972610导致崩溃?如果你指的是“过错”一词,那就意味着另一回事。如果对象没有完全加载到内存中,则会出现故障,只有当您尝试访问内核时,它才会被核心数据透明加载 – LombaX

+0

当抛出异常时Core Data输出的内容是什么? – Tommy

回答

0

崩溃的主要原因:“保存在后台线程容易出错“(http://developer.apple.com/library/ios/#documentation/cocoa/conceptual/CoreData/Articles/cdConcurrency.html//apple_ref/doc/uid/TP40003385-SW7)。当然,我以前读过这个。但是RestKit的问题变得更大了。它适用于“contextForCurrentThread”。因此,您应该可以获得后台线程的唯一上下文(根据相同的文档)。但是你不能从主线程保存它,除非你直接传递它,导致在主线程中这个方法返回另一个上下文。当我看到这个,我认为RestKit为我解决这个问题(在“正常”保存期间,而不是从主线程),但没有。第二件事NSFetchedResultsController。当你从-controllerDidChangeContent:呼叫[self.controller fetchedObjects]你应该准备好了,这个数组可以及时改变。我拿这个数组,并枚举,检索必要的数据。在枚举期间它被改变了(我认为,这是一个NSMutableArray返回的wity类型转为NSArray - 所以这种行为成为可能)。您将永远不会在“默认”行为中看到这一点(当您为每个渲染单元获取objectForIndexPath:的对象时(如Apple示例),但在我的应用程序中,除了包含数据对象外,还有其他单元格。所以我需要生成自己的存储空间,而不是直接使用控制器的提取结果。这样我会建议避免使用NSFetchedResultsController。我用简单的NSManagedObjectDidSaveNotification观察者代替它并每次加载数据。

+0

“阵列改变”是什么意思? [self.controller fetchedObjects]是一个NSArray,所以它不会改变(意味着:不能添加或删除对象,所以计数将保持不变)。但是你必须记住数组的本质:对象的集合 - >如果数组指向的对象之一改变自己(想象指向从“a”变为“b”的NSMutableString),则“内容“数组即使不可变也会更改。所以问题是我提出的两个问题:-P问题与后台管理和[self.controller fetchedObjects] ;-) – LombaX

+0

这是一个错误:不喜欢“枚举时更改数组”。而你错了,返回'NSArray'的方法实际上可以简单地返回'NSMutableArray'(因为NSArray是他的父类)。虽然所有其他人会“认为”它是不可改变的 - 它可以改变。 – kpower

+0

还有一件事。当你枚举对象时,你可以改变它们的参数而没有任何问题。因为这些指针不会改变 - 并且在这里你永远不会得到任何错误。 – kpower