1

我正在为我的应用程序实现备份/恢复功能,但是在我从备份中恢复 sqlite 文件并尝试访问一些数据后,我收到此错误:

Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Object's persistent store is not reachable from this NSManagedObjectContext's coordinator'

回到 ARC 之前,您可以取消 appdelegate 上的 Core Data 对象,然后当您尝试访问 ManagedObjectContext 时它们会被重建。你现在怎么做?

编辑:

那我一定是做错了什么。我可以将托管对象上下文设置为不是只读的,但是当我尝试访问数据时会遇到同样的错误。有什么建议吗?

- (void)restoreDatabase {

    ICAMAppDelegate *appDelegate = (ICAMAppDelegate *)[[UIApplication sharedApplication] delegate];
    appDelegate.managedObjectContext = nil;
    NSError *error;

    // Delete Persistent Store
    NSArray *stores = [[appDelegate persistentStoreCoordinator] persistentStores];
    NSPersistentStore *store = [stores objectAtIndex:0];
    NSURL *storeURL = store.URL;
    [[appDelegate persistentStoreCoordinator] removePersistentStore:store error:&error];
    [[NSFileManager defaultManager] removeItemAtPath:storeURL.path error:&error];

    NSString * databaseName = @"ICAMMobile.sqlite";
    NSString * databaseBackupName = @"ICAMMobile.sqlite.bak";
    NSFileManager *fileManager = [NSFileManager defaultManager];
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *documentsDir = ([paths count] > 0) ? [paths objectAtIndex:0] : nil;

    NSString *backupPath = [documentsDir stringByAppendingPathComponent:databaseBackupName];
    NSString *dbPath = [documentsDir stringByAppendingPathComponent:databaseName];

    if([fileManager fileExistsAtPath:backupPath])
    {
        if (![fileManager copyItemAtPath:backupPath toPath:dbPath error:&error])
        {
            NSLog(@"Failed to create writable database file with message '%@'.", [error localizedDescription]);
        }
        else
        {
            [appDelegate.managedObjectContext reset];
        }
    }
}
4

1 回答 1

6

这是有效的。我需要[appDelegate persistentStoreCoordinator] addPersistentStoreWithType在替换文件后打电话。

编辑: 作为奖励,我也添加了备份数据库方法。

- (void)restoreDatabase {
    ICAMAppDelegate *appDelegate = (ICAMAppDelegate *)[[UIApplication sharedApplication] delegate];
    NSError *error;
    // Delete Persistent Store
    NSArray *stores = [[appDelegate persistentStoreCoordinator] persistentStores];
    NSPersistentStore *store = [stores objectAtIndex:0];
    NSURL *storeURL = store.URL;
    [[appDelegate persistentStoreCoordinator] removePersistentStore:store error:&error];
    [[NSFileManager defaultManager] removeItemAtPath:storeURL.path error:&error];

    NSString * databaseName = @"ICAMMobile.sqlite";
    NSString * databaseBackupName = @"ICAMMobile.sqlite.bak";
    NSFileManager *fileManager = [NSFileManager defaultManager];
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *documentsDir = ([paths count] > 0) ? [paths objectAtIndex:0] : nil;

    NSString *backupPath = [documentsDir stringByAppendingPathComponent:databaseBackupName];
    NSString *dbPath = [documentsDir stringByAppendingPathComponent:databaseName];

    if([fileManager fileExistsAtPath:backupPath])
    {
        if (![fileManager copyItemAtPath:backupPath toPath:dbPath error:&error])
        {
            NSLog(@"Failed to create writable database file with message '%@'.", [error localizedDescription]);
        }
        else
        {
            [[appDelegate persistentStoreCoordinator] addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error];
        }
     }
}


- (void)backupDatabase {
    NSString * databaseName = @"ICAMMobile.sqlite";
    NSString * databaseBackupName = @"ICAMMobile.sqlite.bak";
    NSFileManager *fileManager = [NSFileManager defaultManager];
    NSError *error = nil;
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *documentsDir = ([paths count] > 0) ? [paths objectAtIndex:0] : nil;

    NSString *backupPath = [documentsDir stringByAppendingPathComponent:databaseBackupName];
    NSString *dbPath = [documentsDir stringByAppendingPathComponent:databaseName];

    NSURL *toURL = [NSURL fileURLWithPath:backupPath];

    if([fileManager fileExistsAtPath:backupPath])
    {
        //get rid of the old copy, only one allowed
        [fileManager removeItemAtPath:backupPath error:&error];
    }

    if([fileManager fileExistsAtPath:dbPath])
    {
        if ([fileManager copyItemAtPath:dbPath toPath:backupPath error:&error]) {
            [toURL setResourceValue:[NSNumber numberWithBool:YES] forKey:NSURLIsExcludedFromBackupKey error:&error];
        } else {
            NSLog(@"Failed to create writable database file with message '%@'.", [error localizedDescription]);
        }
    }
}
于 2013-01-29T23:05:16.243 回答