从 ViewController 刷新 AppDelegate 中的 NSPersistentStoreCoordinator [英] Refresh NSPersistentStoreCoordinator in AppDelegate from ViewController

查看:30
本文介绍了从 ViewController 刷新 AppDelegate 中的 NSPersistentStoreCoordinator的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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?

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

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

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

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 - 我认为这反映了您的建议,但我仍然让应用程序在 addPersistentStore 阶段崩溃并显示未解决的错误"日志:

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

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

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] 持久存储是:file://localhost/var/mobile/Applications/D34C6065-8D59-480F-ABA4-9F10C690F26C/Library/

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] 它在被删除之前就在那里

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] 未解决的删除错误 (null), (null)

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

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

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

推荐答案

最好的答案是在 NSPersistentStoreCoordinator 上做一个 -removePersistentStore:error: 然后做一个 <代码>-addPersistentStoreWithType:配置:配置网址:选项:错误:

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

作为这个过程的一部分,我会在 NSManagedObjectContext 上做一个 -reset 然后发布一个 NSNotification 你的视图控制器正在监听然后你的视图控制器可以重新加载它的数据.

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.

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

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

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

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.

这段代码没有任何意义:

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

不回复错误以确定失败,检查从调用返回的BOOL.

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

这篇关于从 ViewController 刷新 AppDelegate 中的 NSPersistentStoreCoordinator的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆