Refresh NSPersistentStoreCoordinator in AppDelegate from ViewController

戏子无情 提交于 2019-12-13 07:36:05

问题


I have an app where the PersistentStoreCoordinator is set up within AppDelegate. I want to load a new sqlite database from a list of saved sqlite files. I'm happy with deleting the existing Persistent Store and sqlite file and replacing the sqlite file with the one loaded from the table. However, how do I reload/refresh the PersistentStoreCoordinator from the ViewController action of selecting the new file? I've tried setting AppDelegate as a delegate of the ViewController, but this seems to create all sorts of circular references within the app. Also, what is the precise method for reloading the PersistentStoreCoordinator?

I've tried this code but it just clears the persistent store without refreshing with the loaded sqlite file (Working.sqlite is the name for the current running version of the sqlite database):

 -  (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];}

OK - I've now modified the code as below, and when I select the row to load I now get a crash when I do the final addition of the new store to the PSC. The error codes are both null, so I'm not sure what is failing. The NSLogs show that the original store has been deleted, and the new version copied in.

-  (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 - I think this reflects your advice but I still get the app crashing at the addPersistentStore stage with the "unresolved error" log:

-  (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();}
 }

Following Marcus' advice, I added the error log on removePersistentStore in the modified code above. The problem occurs in the remove action. The log file ends as follows:

2013-06-01 01:10:02.478 inControl[1238:907] Persistent Store is: file://localhost/var/mobile/Applications/D34C6065-8D59-480F-ABA4-9F10C690F26C/Library/Working.sqlite

2013-06-01 01:10:02.481 inControl[1238:907] It was there before it was deleted

2013-06-01 01:10:02.486 inControl[1238:907] Unresolved error on remove (null), (null)

Final working code following advice from 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();
    }
    } 

回答1:


The best answer is to do a -removePersistentStore:error: on the NSPersistentStoreCoordinator then do a -addPersistentStoreWithType: configuration: configuration URL: options: error:

As part of that process I would do a -reset on the NSManagedObjectContext and then post a NSNotification that your view controller is listening for and then your view controller can reload its data.

You do not need to delete any files from disk.

Update 1

First, you need to tell us what the crash is :)

Second, you are not using the error parameter on the -removePersistentStore... so you might be getting an error there.

Update the question with the crash and it will help to sort this out.

Update 2

This code does not make any sense:

// 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;

If that is accurate then it is wrong. It should be:

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();
}

Do not reply on the error to determine failure, check the BOOL that is returned from the call.



来源:https://stackoverflow.com/questions/16832438/refresh-nspersistentstorecoordinator-in-appdelegate-from-viewcontroller

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!