0

我有一个应用程序,其中在 AppDelegate 中设置了 PersistentStoreCoordinator。我想从保存的 sqlite 文件列表中加载一个新的 sqlite 数据库。我很高兴删除现有的 Persistent Store 和 sqlite 文件并将 sqlite 文件替换为从表中加载的文件。但是,如何从选择新文件的 ViewController 操作中重新加载/刷新 PersistentStoreCoordinator?我尝试将 AppDelegate 设置为 ViewController 的委托,但这似乎会在应用程序中创建各种循环引用。另外,重新加载 PersistentStoreCoordinator 的精确方法是什么?

我已经尝试过这段代码,但它只是清除了持久存储而不刷新加载的 sqlite 文件(Working.sqlite 是当前运行的 sqlite 数据库版本的名称):

 -  (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
        NSString *libraryPath = [NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES) lastObject];
        targetPath = [libraryPath stringByAppendingPathComponent:@"Working.sqlite"]; 
AppDelegate *delegate = [[UIApplication sharedApplication] delegate];

        NSPersistentStore *store = [[delegate.persistentStoreCoordinator persistentStores] lastObject];
        NSError *error;

        NSPersistentStoreCoordinator *storeCoordinator = delegate.persistentStoreCoordinator;
        [storeCoordinator removePersistentStore:store error:&error];
        [[NSFileManager defaultManager] removeItemAtPath:targetPath error:&error];


        NSString *loadPath = [workingDirPath stringByAppendingPathComponent:[directoryContent objectAtIndex:indexPath.row]];
        NSString *loadName = [[directoryContent objectAtIndex:indexPath.row] stringByDeletingPathExtension];
        NSLog(@"selectedPlan is: %@", loadName);


        if (![[NSFileManager defaultManager] copyItemAtPath:loadPath toPath:targetPath error:&error]) {
            NSLog(@"Error: %@", error);
        }



        else {
            [delegate managedObjectContext];
            [delegate managedObjectModel];
            [delegate persistentStoreCoordinator];
           [self.delegate planWasSelectedOnTheFileTableViewController:self];}

好的 - 我现在修改了下面的代码,当我选择要加载的行时,当我最终将新商店添加到 PSC 时,我现在遇到了崩溃。错误代码都是空的,所以我不确定是什么失败了。NSLogs 显示原始存储已被删除,并复制了新版本。

-  (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    NSString *libraryPath = [NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES) lastObject];
    targetPath = [libraryPath stringByAppendingPathComponent:@"Working.sqlite"]; AppDelegate *delegate = [[UIApplication sharedApplication] delegate];

    NSPersistentStore *store = [[delegate.persistentStoreCoordinator persistentStores] lastObject];
    NSError *error;

    NSString *loadPath = [workingDirPath stringByAppendingPathComponent:[directoryContent objectAtIndex:indexPath.row]];
    NSString *loadName = [[directoryContent objectAtIndex:indexPath.row] stringByDeletingPathExtension];
    NSLog(@"selectedPlan is: %@", loadName);
    [delegate.persistentStoreCoordinator removePersistentStore:store error:&error];
    [[NSFileManager defaultManager] removeItemAtPath:targetPath error:&error];

    if ([[NSFileManager defaultManager] fileExistsAtPath:targetPath]){NSLog(@"It's still there!");

    }
    else {NSLog(@"File deleted");}
    [[NSFileManager defaultManager] copyItemAtPath:loadPath toPath:targetPath error:&error];
    if ([[NSFileManager defaultManager] fileExistsAtPath:targetPath]){NSLog(@"File Copied");

    }
    else {NSLog(@"path empty");}
    NSURL *storeURL = [NSURL fileURLWithPath:targetPath];
        error = nil;
    NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
                                 [NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption,
                                 [NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil];

    [delegate.persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:options error:&error]; {            NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
            abort();
        }

       [self.delegate planWasSelectedOnTheFileTableViewController:self];}

Marcus - 我认为这反映了您的建议,但我仍然让应用程序在 addPersistentStore 阶段崩溃,并显示“未解决的错误”日志:

-  (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    AppDelegate *delegate = [[UIApplication sharedApplication] delegate];

    //setting path to current working sqlite file
    NSString *libraryPath = [NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES) lastObject];
    targetPath = [libraryPath stringByAppendingPathComponent:@"Working.sqlite"];

    //setting path to selected sqlite file
    NSString *loadPath = [workingDirPath stringByAppendingPathComponent:[directoryContent objectAtIndex:indexPath.row]];
    NSString *loadName = [[directoryContent objectAtIndex:indexPath.row] stringByDeletingPathExtension];
    NSLog(@"selectedPlan is: %@", loadName);

    // retrieve the store URL
    NSURL * storeURL = [NSURL fileURLWithPath:targetPath];
    NSString *storeName = [storeURL absoluteString];
     NSLog(@"Persistent Store is: %@", storeName);
    if ([[NSFileManager defaultManager] fileExistsAtPath:targetPath]){NSLog(@"It was there before it was deleted");}

    // remove the store
    NSError *error;
    [delegate.persistentStoreCoordinator removePersistentStore:[[delegate.persistentStoreCoordinator persistentStores] lastObject] error:&error];
{NSLog(@"Unresolved error on remove %@, %@", error, [error userInfo]);
    abort();}
error = nil;


    // remove the store file and check it's gone
    [[NSFileManager defaultManager] removeItemAtURL:storeURL error:&error];
    if ([[NSFileManager defaultManager] fileExistsAtPath:targetPath]){NSLog(@"It's still there!");}
        else {NSLog(@"File deleted");}

    // copy in new file and check it's there
    [[NSFileManager defaultManager] copyItemAtPath:loadPath toPath:targetPath error:&error];
        if ([[NSFileManager defaultManager] fileExistsAtPath:targetPath]){NSLog(@"File Copied");}
        else {NSLog(@"path empty");}

    //re-attach the store
    NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
                             [NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption,
                             [NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil];

    [delegate.persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:options error:&error];
    {NSLog(@"Unresolved error on add %@, %@", error, [error userInfo]);
        abort();}
 }

按照 Marcus 的建议,我在上面修改后的代码中添加了 removePersistentStore 上的错误日志。问题出现在删除操作中。日志文件结束如下:

2013-06-01 01:10:02.478 inControl[1238:907] 持久存储是:file://localhost/var/mobile/Applications/D34C6065-8D59-480F-ABA4-9F10C690F26C/Library/Working.sqlite

2013-06-01 01:10:02.481 inControl[1238:907] 在被删除之前它就在那里

2013-06-01 01:10:02.486 inControl[1238:907] 删除时未解决的错误 (null), (null)

遵循 Marcus 的建议的最终工作代码:

-  (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    AppDelegate *delegate = [[UIApplication sharedApplication] delegate];

    //setting path to current working sqlite file
    NSString *libraryPath = [NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES) lastObject];
    targetPath = [libraryPath stringByAppendingPathComponent:@"Working.sqlite"];

    //setting path to selected sqlite file
    NSString *loadPath = [workingDirPath stringByAppendingPathComponent:[directoryContent objectAtIndex:indexPath.row]];
    NSString *loadName = [[directoryContent objectAtIndex:indexPath.row] stringByDeletingPathExtension];
    NSLog(@"selectedPlan is: %@", loadName);

    // retrieve the store URL
    NSURL * storeURL = [NSURL fileURLWithPath:targetPath];
    NSString *storeName = [storeURL absoluteString];
     NSLog(@"Persistent Store is: %@", storeName);
    if ([[NSFileManager defaultManager] fileExistsAtPath:targetPath]){NSLog(@"It was there before it was deleted");}

    // remove the store
    NSError *error;
    NSPersistentStoreCoordinator *psc = [delegate persistentStoreCoordinator];
    NSPersistentStore *ps = [[psc persistentStores] lastObject];
    if (![psc removePersistentStore:ps error:&error]) {
        NSLog(@"Remove Store Failure: %@\n%@", [error localizedDescription], [error userInfo]);
        abort();
    }    error = nil;

    // remove the store file and check it's gone
    [[NSFileManager defaultManager] removeItemAtURL:storeURL error:&error];


    if ([[NSFileManager defaultManager] fileExistsAtPath:targetPath]){NSLog(@"It's still there!");}
        else {NSLog(@"File deleted");}

    // copy in new file and check it's there
    [[NSFileManager defaultManager] copyItemAtPath:loadPath toPath:targetPath error:&error];
        if ([[NSFileManager defaultManager] fileExistsAtPath:targetPath]){NSLog(@"File Copied");}
        else {NSLog(@"path empty");}

    [delegate.managedObjectContext reset];
    //re-attach the store
    NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
                             [NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption,
                             [NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil];

    if (![psc addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:options error:&error]) {
        NSLog(@"Add Store Failure: %@\n%@", [error localizedDescription], [error userInfo]);
        abort();
    }
    } 
4

1 回答 1

2

最好的答案是先做一个-removePersistentStore:error:然后NSPersistentStoreCoordinator再做一个-addPersistentStoreWithType: configuration: configuration URL: options: error:

作为该过程的一部分,我会-resetNSManagedObjectContext然后发布NSNotification您的视图控制器正在侦听的内容,然后您的视图控制器可以重新加载其数据。

您不需要从磁盘中删除任何文件。

更新 1

首先,您需要告诉我们崩溃是什么:)

其次,您没有在 上使用 error 参数,-removePersistentStore...因此您可能会在那里遇到错误。

用崩溃更新问题,这将有助于解决这个问题。

更新 2

这段代码没有任何意义:

// remove the store
NSError *error;
[delegate.persistentStoreCoordinator removePersistentStore:[[delegate.persistentStoreCoordinator persistentStores] lastObject] error:&error];
{NSLog(@"Unresolved error on remove %@, %@", error, [error userInfo]);
abort();}
error = nil;

如果这是正确的,那就错了。它应该是:

NSError *error;
NSPersistentStoreCoordinator *psc = [delegate persistentStoreCoordinator];
NSPersistentStore *ps = [[psc persistentStores] lastObject];
if (![psc removePersistentStore:ps error:&error]) {
  NSLog(@"Failure: %@\n%@", [error localizedDescription], [error userInfo]);
  abort();
}

不要回复错误以确定失败,请检查BOOL调用返回的内容。

于 2013-05-31T19:14:24.200 回答