我有一个应用程序,它首先将一些数据加载到 UIManagedDocument 中,然后执行saveToURL:forSaveOperation:completionHandler:
. 在completionHandler 块中,它会更新这个数据库的各种元素,当它完成后,它会再次保存。
除此之外,该应用程序还有 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;
}