我正在使用UIManagedDocument处理我的应用程序。我几天前发布了另一个问题,但我还没有开始工作。让我们看看我能否做得更好。
我的应用程序需要从plist文件加载一些数据并用它填充数据库。然后,有些参数会一次又一次地改变,我还需要在数据库中加载和更新它们
应用程序应遵循以下顺序:创建/打开数据库,加载数据,更新变量数据
当我试图正确地遵循这个序列时,我的问题就出现了,主要是因为我无法在数据库中创建所有对象之前更新变量数据(因此必须更新的nil变量),而我的变通方法只会让我意外崩溃和不合逻辑的行为
到目前为止,这是我的代码:
在视图代码中:
- (void)viewDidLoad{
[super viewDidLoad];
self.database = [DataHelper opendatabaseAndUseBlock:^{
[self setupFetchedResultsController]; // I pass this method trough a Block because I want it
// to be executed once the database is opened, not before.
}];
}
然后我使用这个包含以下代码的帮助器类“DataHelper”:
@implementation DataHelper
// This method creates and opens the database, then calls the necessary methods
+ (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 withSuccess:success];
completionBlock();
}];
} else if (database.documentState == UIDocumentStateClosed) {
[database openWithCompletionHandler:^(BOOL success) {
[self loadDataIntodatabase:database withSuccess:success];
completionBlock();
}];
} else if (database.documentState == UIDocumentStateNormal) {
[self loadDataIntodatabase:database withSuccess:YES];
completionBlock();
}
return database;
}
// This method loads the "static" data into the database, by reading it from a plist file.
// Once the loading finishes, it should call the last method, for updating the variable data
+ (void)loadDataIntoDatabase:(UIManagedDocument *)database withSuccess:(BOOL)success
{
if (success) {
NSString *path = [[NSBundle mainBundle] pathForResource:@"Data" ofType:@"plist"];
NSArray *plistData = [NSArray arrayWithContentsOfFile:path];
[database.managedObjectContext performBlock:^{
for (NSDictionary *data in plistData) {
[Object createObjectWithData:data inManagedObjectContext:database.managedObjectContext];
}
// Not sure what to do here!!
//[database saveToURL:database.fileURL forSaveOperation:UIDocumentSaveForOverwriting completionHandler:^(BOOL success) {
// [DataHelper updateVariableDataOfDatabase:database];
//}];
// Or...?
//[database updateChangeCount:UIDocumentChangeDone];
// [DataHelper updateVariableDataOfDatabase:database];
}];
} else {
NSLog(@"NO SUCCESS");
}
}
// This last method updates some parameters of the existing data
// in the database, to the ones found in another plist file
+ (void)updateVariableDataOfDatabase:(UIManagedDocument *)database
{
// This path is provisional, should be gotten from an online resource
NSString *path = [[NSBundle mainBundle] pathForResource:@"VariableData" ofType:@"plist"];
NSDictionary *variables = [NSDictionary dictionaryWithContentsOfFile:path];
[database.managedObjectContext performBlock:^{
// Update the objects changing the values of the variable parameters
// to the ones found in "variables"
// Now I should save the changes, or maybe not?
//[database saveToURL:database.fileURL forSaveOperation:UIDocumentSaveForOverwriting completionHandler:nil];
// Or...
//[database updateChangeCount:UIDocumentChangeDone];
}];
}
@end
如果我使用“saveToURL”方法,虽然它似乎不正确,但它正确地执行加载序列,因为在所有数据都已加载到数据库之前不会执行最后一个方法。但是,当尝试执行许多操作时,应用程序会随机崩溃(内部有很多节省,比如删除,更新或重新加载)。
另一方面,通过使用“updateChangeCount”,应用程序不再崩溃,但序列不能正常工作:变量数据不会更新,应用程序找不到那里的对象,在数据库,等等。如果我在每个动作之间等待2分钟左右,那么是的,它有效......但这不是我想要的。
我真的很感激这里的帮助,这耗费了我的时间,而且这个项目的截止日期非常接近:(
非常感谢!
答案 0 :(得分:0)
有一段时间过去了,希望你已经在这里解决了你的问题,但为了防止我在过去几个月里一直在与一堆UIManagedDocument相关的问题进行斗争,所以我感到很痛苦。你在这里所做的与我最近在一个项目中需要做的非常相似。
不幸的是,关于如何保存(或不保存)UIManagedDocument的文档和各种建议似乎在某种程度上到处都是。我使用saveToURL和updateChangeCount方法找到了类似的结果,但updateChangeCount方法似乎不太经常导致保存错误。但我认为这不会影响你的问题。
只要您只有一个线程访问您的文档,并且只要您只为一个文档打开一个文档,您实际上不需要保存,它将自动保存在该上下文中。需要保存以将更改从该上下文推送到其他上下文(UIManagedDocument有两个)并最终到云和其他设备。在completionHandler中有两层performBlock,这可能会使事情变得复杂,导致多个线程可能同时以不可预测的顺序访问您的数据库。当我完成所有预加载和设置时,它只是在completionHandler中顺序执行,后跟相应的opendatabaseAndUseBlock,它永远不会崩溃。