如何正确初始化,使用和保存UIManagedDocument

时间:2012-05-09 10:41:40

标签: objective-c ios core-data uimanageddocument

我正在使用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分钟左右,那么是的,它有效......但这不是我想要的。

我真的很感激这里的帮助,这耗费了我的时间,而且这个项目的截止日期非常接近:(
非常感谢!

1 个答案:

答案 0 :(得分:0)

有一段时间过去了,希望你已经在这里解决了你的问题,但为了防止我在过去几个月里一直在与一堆UIManagedDocument相关的问题进行斗争,所以我感到很痛苦。你在这里所做的与我最近在一个项目中需要做的非常相似。

不幸的是,关于如何保存(或不保存)UIManagedDocument的文档和各种建议似乎在某种程度上到处都是。我使用saveToURL和updateChangeCount方法找到了类似的结果,但updateChangeCount方法似乎不太经常导致保存错误。但我认为这不会影响你的问题。

只要您只有一个线程访问您的文档,并且只要您只为一个文档打开一个文档,您实际上不需要保存,它将自动保存在该上下文中。需要保存以将更改从该上下文推送到其他上下文(UIManagedDocument有两个)并最终到云和其他设备。在completionHandler中有两层performBlock,这可能会使事情变得复杂,导致多个线程可能同时以不可预测的顺序访问您的数据库。当我完成所有预加载和设置时,它只是在completionHandler中顺序执行,后跟相应的opendatabaseAndUseBlock,它永远不会崩溃。