У меня есть приложение, которое сначала загружает некоторые данные в UIManagedDocument, а затем выполняет saveToURL:forSaveOperation:completionHandler:
. Внутри блока completeHandler он обновляет различные элементы этой базы данных, а когда это сделано, он делает еще одно сохранение.
Кроме того, в приложении есть 3 кнопки, которые перезагружают данные, повторно обновляют данные и удаляют один объект базы данных соответственно. В каждом методе кнопки последняя инструкция также является сохранением.
Когда я запускаю все это в симуляторе, все идет гладко. А в устройстве нет. Постоянно вылетает. Я заметил, что обычно происходит сбой при нажатии кнопки "удалить" или при перезагрузке или повторном обновлении базы данных. И это всегда в операции saveToURL
.
На мой взгляд, проблема возникает, когда есть несколько потоков, сохраняющих базу данных. Поскольку устройство выполняет код медленнее, возможно, несколько сохранений приходят одновременно, и приложение не может правильно их обрабатывать. Кроме того, иногда кнопка удаления не удаляет объект и говорит, что он не существует (когда он существует).
Я совершенно озадачен этим, и все эти операции сохранения должны быть сделаны ... На самом деле, если я их уберу, приложение ведет себя еще более бессвязно.
Любые предложения о том, что я могу сделать, чтобы решить эту проблему? Большое спасибо!
[Изменить] Здесь я публикую проблемный код. Для первой загрузки данных я использую вспомогательный класс, в частности, с двумя этими методами:
+ (void)loadDataIntoDatabase:(UIManagedDocument *)database
{
[database.managedObjectContext performBlock:^{
// Read from de plist file and fill the database
[database saveToURL:database.fileURL forSaveOperation:UIDocumentSaveForOverwriting completionHandler:^(BOOL success) {
[DataHelper completeDataOfDatabase:database];
}];
}
+ (void)completeDataOfDatabase:(UIManagedDocument *)database
{
[database.managedObjectContext performBlock:^{
// Read from another plist file and update some parameters of the already existent data (uses NSFetchRequest and works well)
// [database saveToURL:database.fileURL forSaveOperation:UIDocumentSaveForOverwriting completionHandler:nil];
[database updateChangeCount:UIDocumentChangeDone];
}];
}
И в представлении у меня есть 3 метода действий, например:
- (IBAction)deleteButton {
[self.database.managedObjectContext performBlock:^{
NSManagedObject *results = ;// The item to delete
[self.database.managedObjectContext deleteObject:results];
// [self.database saveToURL:self.database.fileURL forSaveOperation:UIDocumentSaveForOverwriting completionHandler:NULL];
[self.database updateChangeCount:UIDocumentChangeDone];
}];
}
- (IBAction)reloadExtraDataButton {
[DataHelper loadDataIntoDatabase:self.database];
// [self.database saveToURL:self.database.fileURL forSaveOperation:UIDocumentSaveForOverwriting completionHandler:NULL];
[self.database updateChangeCount:UIDocumentChangeDone];
}
- (IBAction)refreshDataButton {
[DataHelper completeDataOfDatabase:self.database];
//[self.database saveToURL:self.database.fileURL forSaveOperation:UIDocumentSaveForOverwriting completionHandler:NULL];
[self.database updateChangeCount:UIDocumentChangeDone];
}
[Редактировать 2] Дополнительный код: Прежде всего, начальное представление выполняет viewDidLoad следующим образом:
- (void)viewDidLoad{
[super viewDidLoad];
self.database = [DataHelper openDatabaseAndUseBlock:^{
[self setupFetchedResultsController];
}];
}
Вот как выглядит метод setupFetchedResultsController:
- (void)setupFetchedResultsController
{
NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"Some entity name"];
request.sortDescriptors = [NSArray arrayWithObject:[NSSortDescriptor sortDescriptorWithKey:@"name" ascending:YES selector:@selector(localizedCaseInsensitiveCompare:)]];
self.fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:request
managedObjectContext:self.database.managedObjectContext
sectionNameKeyPath:nil
cacheName:nil];
}
Каждое представление приложения (у него есть вкладки) имеет другой setupFetchedResultsController для отображения различных сущностей, содержащихся в базе данных.
Теперь во вспомогательном классе это первый метод класса, который выполняется через viewDidLoad каждого представления:
+ (UIManagedDocument *)openDatabaseAndUseBlock:(completion_block_t)completionBlock
{
NSURL *url = [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
url = [url URLByAppendingPathComponent:@"Database"];
UIManagedDocument *database = [[UIManagedDocument alloc] initWithFileURL:url];
if (![[NSFileManager defaultManager] fileExistsAtPath:[database.fileURL path]]) {
[database saveToURL:database.fileURL forSaveOperation:UIDocumentSaveForCreating completionHandler:^(BOOL success) {
[self loadDataIntoDatabase:database];
completionBlock();
}];
} else if (database.documentState == UIDocumentStateClosed) {
// Existe, pero cerrado -> Abrir
[database openWithCompletionHandler:^(BOOL success) {
[self loadDataIntoDatabase:database];
completionBlock();
}];
} else if (database.documentState == UIDocumentStateNormal) {
[self loadDataIntoDatabase:database];
completionBlock();
}
return database;
}