CoreData无法完成错误
我有一个非常恼人的问题,我似乎无法修复。
当我发送一条消息被保存到核心数据时,我有一个视图,当它完成时,它向数据库询问一个随机消息(句子),并将其保存到数据库中的另一行。
如果我做了最后一部分硬编码,没有从数据库中获取数据,它的工作都很好,但是一旦我从数据库中获取随机行,它就会变得疯狂。
在我的AppDelegate.m中:
- (void)save { NSAssert(self.context != nil, @"Not initialized"); NSError *error = nil; BOOL failed = [self.context hasChanges] && ![self.context save:&error]; NSAssert1(!failed,@"Save failed %@",[error userInfo]); } - (NSString*)selectRandomSentence { NSFetchRequest *request = [[NSFetchRequest alloc] init]; NSEntityDescription *entity = [NSEntityDescription entityForName:@"Sentences" inManagedObjectContext:self.managedObjectContext]; [request setEntity:entity]; NSError *error = nil; NSUInteger count = [self.context countForFetchRequest:request error:&error]; NSUInteger offset = count - (arc4random() % count); [request setFetchOffset:offset]; [request setFetchLimit:1]; NSArray *sentenceArray = [self.context executeFetchRequest:request error:&error]; [request release]; return [[sentenceArray objectAtIndex:0] sentence]; } - (NSManagedObjectContext *)context { if (_managedObjectContext != nil) return _managedObjectContext; NSPersistentStoreCoordinator *coordinator = [self coordinator]; if (coordinator != nil) { _managedObjectContext = [[NSManagedObjectContext alloc] init]; [_managedObjectContext setPersistentStoreCoordinator:coordinator]; } return _managedObjectContext; }
在我的ChatController.m中:
- (void)didRecieveMessage:(NSString *)message { [self addMessage:message fromMe:NO]; } #pragma mark - #pragma mark SendControllerDelegate - (void)didSendMessage:(NSString*)text { [self addMessage:text fromMe:YES]; } #pragma mark - #pragma mark Private methods - (void)responseReceived:(NSString*)response { [self addMessage:response fromMe:NO]; } - (void)addMessage:(NSString*)text fromMe:(BOOL)fromMe { NSAssert(self.repository != nil, @"Not initialized"); Message *msg = [self.repository messageForBuddy:self.buddy]; msg.text = text; msg.fromMe = fromMe; if (fromMe) { [self.bot talkWithBot:text]; } [self.repository asyncSave]; [self.tableView reloadData]; [self.tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:[self.buddy.messages count] - 1] atScrollPosition:UITableViewScrollPositionBottom animated:YES]; }
在我的OfflineBot.m中:
- (void)talkWithBot:(NSString *)textFromMe { AppDelegate *delegate = [[UIApplication sharedApplication] delegate]; [self didRecieveMessage:[delegate selectRandomSentence]]; } - (void)didRecieveMessage:(NSString *)message { if ([self.delegate respondsToSelector:@selector(didRecieveMessage:)]) [self.delegate didRecieveMessage:message]; }
Repository.m
- (Message*)messageForBuddy:(Buddy*)buddy { Message *msg = [self.delegate entityForName:@"Message"]; msg.source = buddy; [self.delegate.managedObjectContext refreshObject:buddy mergeChanges:YES]; return msg; } - (void)asyncSave { [self.delegate save]; }
错误:
2012-08-10 00:28:20.526聊天[13170:c07] *声明失败 – [AppDelegate保存],/ Users / paulp /桌面/testing任务/课程/ AppDelegate.m :28 2012-08-10 00:28 :20.527聊天[13170:c07] *终止应用程序,由于未捕获的exception'NSInternalInconsistencyException',原因:'保存失败{types=不可变的字典,计数= 2,条目=> 1:{内容=“NSAffectedObjectsErrorKey”} =(“( entity:Sentences; id:0x6b8bf10; data:)“)2:{contents =”NSUnderlyingException“} = CoreData无法履行'0x6b8bf10'的错误}
我究竟做错了什么?
更新我指出了这一行的错误:
NSArray *sentenceArray = [self.context executeFetchRequest:request error:&error];
当我执行该行时,我得到错误…那就是在获取数据时。 但是,当将新数据保存到Messages实体时,似乎会出现错误。 随机句是从句子中提取的。
在将asyncSave方法直接更改为保存(因此不使用新线程)后,它将保存第一个聊天,但是之后没有任何操作。 它死了。
更新这一切似乎在我didFinishLaunchingWithOptions
使用这个工作:
[self.context setRetainsRegisteredObjects:YES];
我明白CodeData对象模型上下文不会释放它的对象,这似乎是添加和保存之间的问题。 但为什么?
将 Core Data对象“ 保存 ” 在不同的行中概念上并不是真的可行。 请记住,核心数据是一个对象图,而不是数据库。
如果你想“重新定位”你的句子,最好的办法是摧毁它并重新创build它。 如果你想保留旧的实例,只需创build一个新的实例,然后从现有的属性中填写。
为了销毁,使用
[self.context deleteObject:sentenceObject];
重新使用
Sentence *newSentence = [NSEntityDescription insertNewObjectForEntityForName: "Sentences" inManagedObjectContext:self.context]; newSentence.sentence = sentenceObject.sentence; // fill in other properties, then [self.context save:error];
如果您想了解这一点,请查看“核心数据编程指南”的“使用pipe理对象”一节中的“ 复制和复制粘贴 ”。
嗯。 遵循本指南,您是否正确实施了并发? 在multithreading中使用核心数据时,您看到的问题是常见的问题。 对象在您的“后台上下文”中被删除,然后被另一个上下文访问。 在删除之后但在保存之前在背景上下文中调用[context processPendingChanges]
可能会有所帮助。
另外还有一个关于优化核心数据性能的WWDC 2010会议(137),这个会议将会被删除一些。
当您执行提取时,Core Data将返回与您提供的谓词相匹配的对象集合。 这些对象实际上并没有设置属性值。 这是当你访问一个属性,核心数据返回到商店“解雇故障” – 用商店的数据填充属性。 核心数据进入商店以获取对象的属性值,但该对象不存在于持久性存储中时,发生“无法完成错误…”exception。 pipe理对象的上下文认为它应该存在,这就是为什么它可以尝试错误 – 这是问题所在。 导致抛出exception的上下文不知道这个对象已经被别的东西(如另一个上下文)从存储中删除了。
注意上面的“并发指南”现在已经过时了,应该使用父 – 子上下文和专用队列并发而不是旧的线程约束模型。 亲子上下文很可能遇到“无法完成错误……”,原因很多。 请提交文档错误或使用反馈表单来请求更新并发指南。
检查核心数据机制。 “Faulting减less了应用程序消耗的内存量,故障是代表尚未完全实现的pipe理对象的占位符对象,或代表关系的集合对象:”
发生这种情况是因为在完成获取第一个调用的所有关系之前,将“随机消息”添加到新行中。
你可以在第一次调用时添加一个预取,以避免延迟加载,我相信这个问题将被解决。
这是我们如何做预取的请求:
[request setRelationshipKeyPathsForPrefetching:[NSArray arrayWithObjects:@"whatEverOfYourWillNumberOne",@"whatEverOfYourWillNumberTwo", nil]];
希望有所帮助。
我修改了NSFetchedResultsController的“cacheName”string为nil的错误。
NSFetchedResultsController * aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:self.managedObjectContext sectionNameKeyPath:nil cacheName: @“Root” nil ];