Подтвердить что ты не робот

CoreData не может выполнить ошибку для

У меня есть действительно раздражающая проблема, которую я просто не могу понять.

У меня есть представление, когда я отправляю сообщение, которое сохраняется в Core Data, когда это было сделано, он запросил базу данных для случайного сообщения (предложения) и сохранил ее также в другой строке в базе данных.

Если я делаю последнюю часть жестко запрограммированной, не получая данные из БД, она работает отлично и денди, но как только я получаю случайную строку из БД, она сходит с ума.

В моем 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];
}

В My OnlineBot.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 save],/Users/paulp/Desktop/TestTask/Classes/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 = "NSUnderatingException" } = CoreData не может выполнить ошибку для "0x6b8bf10 '}

Что я делаю неправильно?

Обновление Я указал ошибку на эту строку:

NSArray *sentenceArray = [self.context executeFetchRequest:request error:&error];

Когда я выполняю эту строку, я получаю ошибку... то есть при извлечении данных. Ошибка, однако, кажется, появляется при сохранении новых данных в сущности Messages. Случайное предложение выбирается из предложений.

После того, как я изменил метод asyncSave на сохранение напрямую (таким образом, не используя новый поток), он сохраняет первый чат, но после этого ничего не происходит. Он умирает.

Обновление Кажется, все это работает с помощью этого в didFinishLaunchingWithOptions:

[self.context setRetainsRegisteredObjects:YES];

Я понимаю, что здесь Контекст объектной модели CodeData не выпускает свои объекты, что, по-видимому, является проблемой между добавлением и сохранением betweens. Но почему?

4b9b3361

Ответ 1

На самом деле концептуально невозможно "сохранить" объекты Core Data "в разных строках". Помните, что Core Data - это граф объектов, а не база данных.

Если вы хотите "переместить" ваше предложение, лучший способ - уничтожить его и воссоздать. Если вы хотите сохранить старый экземпляр, просто создайте новый, а затем заполните свойства из существующего.

Для уничтожения используйте

[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];

Если вы хотите прочитать об этом, посмотрите "Копирование и копирование и вставка" в разделе "Использование управляемых объектов" в разделе "Программирование основных данных" Руководство".

Ответ 2

Хм. Правильно ли вы выполняете concurrency после это руководство? Проблема, которую вы видите, является общей при использовании основных данных в нескольких потоках. Объект был удален в вашем "фоновом контексте", а затем к нему обратился другой контекст. Вызов [context processPendingChanges] в фоновом контексте после удаления, но до сохранения может помочь.

Существует также сессия WWDC 2010 (137) по оптимизации производительности данных ядра, которая идет на удаление бит.

Когда вы выполняете извлечение, Core Data возвращает коллекцию объектов, соответствующих предикату, который вы указали. Эти объекты еще не имеют своих значений свойств. Это когда вы получаете доступ к свойству, которое Core Data возвращается в хранилище, чтобы "запустить ошибку" - заполнить свойство данными из хранилища. "Не удалось выполнить ошибку..." исключения происходят, когда Core Data переходит в хранилище, чтобы получить значения свойств для объекта, но объект не существует в постоянном хранилище. Контекст управляемого объекта думал, что он должен существовать, поэтому он может попытаться по ошибке - в чем проблема. Контекст, из-за которого возникло исключение, не знал, что этот объект был удален из хранилища чем-то другим (например, другим контекстом).

Обратите внимание, что приведенное выше руководство concurrency теперь устарело, вы должны использовать контексты родителя-ребенка и приватную очередь concurrency, а не более старую модель ограничения контентов. Контексты родительского ребенка гораздо менее вероятны, чтобы столкнуться с "Не удалось выполнить ошибку..." по многим причинам. И, пожалуйста, зарегистрируйте ошибку документации или используйте форму обратной связи, чтобы запросить обновление руководства concurrency.

Ответ 3

проверить механизм основных данных. "Неисправность уменьшает объем памяти, потребляемой вашим приложением. Ошибка - это объект-заполнитель, который представляет управляемый объект, который еще не полностью реализован, или объект коллекции, который представляет взаимосвязь:"

Ответ 4

Это происходит из-за того, что вы добавляете "случайное сообщение" в свою новую строку до завершения извлечения всех ваших отношений первого вызова.

Вы можете добавить предварительную выборку к вашему 1-му звонку, чтобы избежать ленивой загрузки, и проблема будет решена, я полагаю.

Вот как мы можем сделать предварительную выборку для запроса:

[request setRelationshipKeyPathsForPrefetching:[NSArray arrayWithObjects:@"whatEverOfYourWillNumberOne",@"whatEverOfYourWillNumberTwo", nil]];

Надеюсь, что это поможет.

Ответ 5

Я исправил ошибку с изменением строки NSFetchedResultsController "cacheName" до нуля.

NSFetchedResultsController * aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest: fetchRequest managedObjectContext: self.managedObjectContext sectionNameKeyPath: nil cacheName: @ "Root" ноль]