CoreData无法解决问题

Pau*_*len 33 core-data objective-c nsmanagedobject nsmanagedobjectcontext ios

我有一个非常烦人的问题,我似乎无法修复.

我有一个视图,当我发送一条消息,保存到核心数据,当它完成时它向数据库询问随机消息(句子)并将其保存到数据库中的另一行.

如果我最后一部分硬编码,没有从数据库中获取数据,它可以正常工作,但是只要我从数据库中获取随机行就会发疯.

在我的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;
}
Run Code Online (Sandbox Code Playgroud)

在我的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];
}
Run Code Online (Sandbox Code Playgroud)

在我的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];
}
Run Code Online (Sandbox Code Playgroud)

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];
}
Run Code Online (Sandbox Code Playgroud)

错误:

2012-08-10 00:28:20.526聊天[13170:c07] *断言失败 - [AppDelegate save],/ Users/paulp/Desktop/TestTask/Class/AppDelegate.m:28 2012-08-10 00:28 :20.527聊天[13170:c07]*由于未捕获的异常'NSInternalInconsistencyException'终止应用程序,原因:'保存失败{type = immutable dict,count = 2,entries => 1:{contents ="NSAffectedObjectsErrorKey"} =("( entity:Sentences; id:0x6b8bf10; data:)")2:{contents ="NSUnderlyingException"} = CoreData无法解决'0x6b8bf10'}的错误

我究竟做错了什么?

更新 我将错误指向此行:

NSArray *sentenceArray = [self.context executeFetchRequest:request error:&error];
Run Code Online (Sandbox Code Playgroud)

当我执行该行时,我收到错误...即获取数据时.但是,在将新数据保存到Messages实体时,似乎会出现错误.随机句子来自句子.

在我将asyncSave方法更改为直接保存(因此不使用新线程)后,它保存了第一个聊天,但之后没有任何内容.它死了.

更新 这一切似乎在我的使用中工作didFinishLaunchingWithOptions:

[self.context setRetainsRegisteredObjects:YES];
Run Code Online (Sandbox Code Playgroud)

据我所知,CodeData对象模型上下文不释放它的对象,这似乎是添加和保存之间的问题.但为什么?

que*_*ish 62

嗯.您是否按照本指南正确实现并发?当您跨多个线程使用核心数据时,您看到的问题是常见问题.对象在您的"背景上下文"中被删除,然后被另一个上下文访问.[context processPendingChanges]在删除之后但在保存之前调用您的背景上下文可能会有所帮助.

还有一个关于优化核心数据性能的WWDC 2010会议(137),该会议将删除一些内容.

执行获取时,Core Data会返回与您提供的谓词匹配的对象集合.那些对象实际上并没有设置它们的属性值.当您访问Core Data返回商店以"触发故障"的属性时 - 使用来自商店的数据填充属性."无法完成错误......"当Core Data进入商店获取对象的属性值时会发生异常,但该对象在持久性存储中不存在.托管对象上下文认为它应该存在,这就是它可以尝试故障的原因 - 这就是问题所在.导致抛出异常的上下文不知道该对象已被其他东西(如另一个上下文)从存储中删除.

注意上面的并发指南现在已经过时了,您应该使用父子上下文和私有队列并发而不是旧的线程限制模型.由于许多原因,亲子情境不太可能遇到"无法履行错误......".请提交文档错误或使用反馈表来请求更新并发指南.

  • +1我认为这个答案实际上解决了OP问题中的技术问题 (3认同)

Mun*_*ndi 6

从概念上讲," 在不同的行中 " " 保存 "核心数据对象并不是真的可行.请记住,Core Data是一个对象图,而不是一个数据库.

如果你想"重新定位"你的句子,最好的方法是销毁它并重新创建它.如果要保留旧实例,只需创建一个新实例,然后从现有实例中填充属性.

对于破坏,使用

[self.context deleteObject:sentenceObject];
Run Code Online (Sandbox Code Playgroud)

要重新创建,请使用

Sentence *newSentence = [NSEntityDescription insertNewObjectForEntityForName:
  "Sentences" inManagedObjectContext:self.context];
newSentence.sentence = sentenceObject.sentence;
// fill in other properties, then
[self.context save:error];
Run Code Online (Sandbox Code Playgroud)

如果您想阅读此内容,请查看"核心数据编程指南"的"使用管理对象"部分中的" 复制和复制并粘贴 ".