"Основные данные не могут выполнить ошибку" для объектов, созданных в appDelegate managedObjectContext в основном потоке

Я ошибочно создал группу объектов в фоновом потоке, в результате чего был создан новый файл managedObjectContext, в котором были сохранены объекты.

Это привело к тому, что многочисленные "основные данные не могли выполнить ошибку" произошли в моем реальном приложении. Обратите внимание: я не пытаюсь удалить эти объекты - это проблема с тем, как они были созданы, когда я попытаюсь снова их сохранить в контексте делегирования приложения (основного) в основном потоке.

Дело в том, что я вижу эту ошибку для других объектов, объектов другого типа. Они могут быть связаны с объектами, созданными в фоновом потоке, хотя сами они не были созданы в фоновом потоке.

Я смущен тем, как это могло произойти. Как я могу получить ошибку "Основные данные не могут выполнить ошибку" для объекта, не созданного в фоновом потоке, но в контексте делегирования приложения (основного)?

И есть ли вообще способ вернуться и исправить эту ошибку в живых приложениях моих пользователей?

Позвольте мне ссылаться на мой другой вопрос, через который я обнаружил эту ошибку: "Основные данные не могут выполнить ошибку" для объектов, которые не были удалены

Я написал новый вопрос, потому что я чувствую, что это другая проблема, хотя она определенно связана.

Вот код, который создал объекты в фоновом потоке:

- (void)friendPickerViewControllerDidChooseFriends:(NSArray *)friends {

 __ENTERING_METHOD__
 if (friends.count > 0) {
 [[FacebookHelper sharedManager] friendPickerController].navigationController.navigationBar.userInteractionEnabled = NO;


 [self startProgressIndicator];
 [self performSelectorInBackground:@selector(importFriends:) withObject:friends];
 }
 else {
 [self dismissModalImportViewControllerAnimated];//releases picker delegates, etc
 }
}



#pragma mark -
#pragma mark Import Friend
- (void)importFriends:(NSArray*)friends {

 __ENTERING_METHOD__
 for (NSDictionary<fbgraphuser> *friend in friends) {

 [self importFriend:friend withCompletion:^(void){

 CGFloat friendNumber = [friends indexOfObject:friend]+1;
 CGFloat friendCount = friends.count;
 self.importProgress = friendNumber/friendCount;
 }];
 }
}

- (void)importFriend:(NSDictionary<fbgraphuser>*)friend withCompletion:( void (^) (void) )completionBlock {

 __ENTERING_METHOD__
 Person *myNewPerson = [GetObjectArrayHelper createNewPersonMocSaveNew:YES];

 myNewPerson.facebookID = friend.id;
 myNewPerson.facebookName = friend.name;

 NSString *nameFirst = [friend.first_name stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
 NSString *nameLast = [friend.last_name stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];


 NSString *imageID = friend.id;
 UIImage *pickedImage = nil;
 if(imageID){
 pickedImage = [FacebookHelper imageForObject:imageID];
 }

 DLog(@"pickedImage:%@",pickedImage);

 if(pickedImage){
 [self setImagesForFacebookImage:pickedImage forPerson:myNewPerson];
 }

 //we should ALWAYS have a name
 [Helper changePerson:myNewPerson firstName:nameFirst lastName:nameLast];

 if(completionBlock) {
 completionBlock();
 }
}


- (void)finishedImporting {

 __ENTERING_METHOD__
 [SVProgressHUD showSuccessWithStatus:[self completeString]];
 [self performSelector:@selector(dismissModalImportViewControllerAnimated) withObject:nil afterDelay:SV_PROGRESS_HUD_SUCCESS_DELAY];
}

- (void)dismissModalImportViewControllerAnimated {

 __ENTERING_METHOD__

 [Helper mocSave];//THIS SAVES IN THE APP DELEGATE MANAGED OBJECT CONTEXT -

 [SVProgressHUD dismiss];

 [self dismissViewControllerAnimated:YES completion:^(void){

 [[FacebookHelper sharedManager] friendPickerController].delegate = nil;
 [[FacebookHelper sharedManager] friendPickerController].navigationController.navigationBar.userInteractionEnabled = YES;
 }];
}
</fbgraphuser></fbgraphuser>

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

Почему ОНИ "Основные данные не могут выполнить ошибку" аварии? (Я понимаю, почему любой объект, созданный здесь или в вызванном здесь методе, получит его).

Кроме того, как только я выясню, почему этот беспорядок произошел (и исправить код, вызвавший его), мне нужно исправить объекты-изгои в реальных приложениях моих пользователей. Я мог бы использовать некоторые советы по этому поводу!

1 ответ

Основываясь на вашем вопросе и ваших комментариях, вы:

  • Использование одного управляемого объекта в нескольких потоках.
  • Не принимайте никаких мер предосторожности, чтобы справиться с тем, что NSManagedObjectContext не является потокобезопасным.

В результате вы получаете странные, запутывающие сбои.

Это именно то, чего можно было бы ожидать в этой ситуации. Использование контекста управляемого объекта в нескольких потоках без принятия мер предосторожности - это, по сути, рецепт сбоев и путаницы. Эти сбои могут не иметь большого смысла, потому что вы нарушаете внутреннее состояние контекста.

Если вы хотите использовать контекст более чем в одном потоке, вы должны использовать одну из опций ограничения очереди (NSMainQueueConcurrencyType или NSPrivateQueueConcurrencyType), а затем вы должны поместить весь код, который использует контекст или любой объект, извлеченный из них в performBlock: или performBlockAndWait:. (Исключение: если вы используете NSMainQueueConcurrencyType и знаете, что ваш код находится в основном потоке, вы можете просто использовать контекст напрямую). Вы также можете использовать свой собственный механизм блокировки через что-то вроде NSLock, но NSLock, потоки уже достаточно сложны для большинства людей.

Как правило, лучше использовать один контекст для потока, либо как родительский/дочерний контексты, либо как независимые контексты, но вышеприведенный подход также работает.

Если вам удалось сохранить фиктивные объекты в результате этого, единственное реальное средство - получить эти объекты и либо исправить их, либо удалить. Как идентифицировать эти объекты зависит от ваших данных model--, нет ли универсального теста для "является ли этот объект дерьмом?". Любые проверки зависят от того, что ваше приложение считает правильным.

licensed under cc by-sa 3.0 with attribution.