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

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

问题描述

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



我试过这个代码,但它只是清除持久存储,而不刷新加载的sqlite文件(工作。 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错误:&错误];
[[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。错误代码都是null,所以我不知道什么是失败。 NSLogs显示原始存储已删除,并且新版本已复制。

   - (void)tableView: *)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:&
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(@未解析的错误%@,%@,错误,[错误userInfo]);
abort();
}

[self.delegate planWasSelectedOnTheFileTableViewController:self];}

Marcus - 我认为这反映了你的建议,但我仍然得到应用程序崩溃在addPersistentStore阶段与未解决的错误日志:

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

//设置当前工作sqlite文件的路径
NSString * libraryPath = [NSSearchPathForDirectoriesInDomains(NSLibraryDirectory,NSUserDomainMask,YES)lastObject];
targetPath = [libraryPath stringByAppendingPathComponent:@Working.sqlite];

//设置所选sqlite文件的路径
NSString * loadPath = [workingDirPath stringByAppendingPathComponent:[directoryContent objectAtIndex:indexPath.row]];
NSString * loadName = [[directoryContent objectAtIndex:indexPath.row] stringByDeletingPathExtension];
NSLog(@selectedPlan is:%@,loadName);

//检索商店URL
NSURL * storeURL = [NSURL fileURLWithPath:targetPath];
NSString * storeName = [storeURL absoluteString];
NSLog(@Persistent Store is:%@,storeName);
if([[NSFileManager defaultManager] fileExistsAtPath:targetPath]){NSLog(@它之前被删除);}

//删除存储
NSError *错误;
[delegate.persistentStoreCoordinator removePersistentStore:[[delegate.persistentStoreCoordinator persistentStores] lastObject] error:& error];
{NSLog(@删除时出现未解决的错误%@,%@,错误,[错误userInfo]);
abort();}
error = nil;


//删除存储文件并检查它是否
[[NSFileManager defaultManager] removeItemAtURL:storeURL 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);}
$ b b //重新附加存储
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(@添加%@,%@时出现未解决的错误,错误,[error userInfo]);
abort();}
}

错误日志上的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] remove(null),(null)时出现未解决的错误



根据Marcus的建议,最终工作代码:

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

//设置当前工作sqlite文件的路径
NSString * libraryPath = [NSSearchPathForDirectoriesInDomains(NSLibraryDirectory,NSUserDomainMask,YES)lastObject];
targetPath = [libraryPath stringByAppendingPathComponent:@Working.sqlite];

//设置所选sqlite文件的路径
NSString * loadPath = [workingDirPath stringByAppendingPathComponent:[directoryContent objectAtIndex:indexPath.row]];
NSString * loadName = [[directoryContent objectAtIndex:indexPath.row] stringByDeletingPathExtension];
NSLog(@selectedPlan is:%@,loadName);

//检索商店URL
NSURL * storeURL = [NSURL fileURLWithPath:targetPath];
NSString * storeName = [storeURL absoluteString];
NSLog(@Persistent Store is:%@,storeName);
if([[NSFileManager defaultManager] fileExistsAtPath:targetPath]){NSLog(@它之前被删除);}

//删除存储
NSError *错误;
NSPersistentStoreCoordinator * psc = [delegate persistentStoreCoordinator];
NSPersistentStore * ps = [[psc persistentStores] lastObject];
if(![psc removePersistentStore:ps错误:&错误]){
NSLog(@删除存储失败:%@ \\\
%@,[error localizedDescription],[error userInfo] );
abort();
} error = nil;

//删除存储文件并检查它是否
[[NSFileManager defaultManager] removeItemAtURL:storeURL error:& error];


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

//在新文件中复制并检查它
[[NSFileManager defaultManager] copyItemAtPath:loadPath toPath:targetPath error:&
if([[NSFileManager defaultManager] fileExistsAtPath:targetPath]){NSLog(@File Copied);}
else {NSLog(@path empty);}
$ b b [delegate.managedObjectContext reset];
//重新附加存储
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(@添加存储失败:%@ \\\
%@,[error localizedDescription],[error userInfo]);
abort();
}
}


解决方案

最好的答案是在 NSPersistentStoreCoordinator 上执行 -removePersistentStore:error:,然后执行 addPersistentStoreWithType:configuration:configuration URL:options:error:



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



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



更新1

首先,您需要告诉我们崩溃的原因:)

-removePersistentStore ... 上的错误参数,因此您可能会收到错误。



更新问题



更新2



此代码不会产生任何错误感觉:

  //删除存储
NSError * error;
[delegate.persistentStoreCoordinator removePersistentStore:[[delegate.persistentStoreCoordinator persistentStores] lastObject] error:& error];
{NSLog(@删除时出现未解决的错误%@,%@,错误,[错误userInfo]);
abort();}
error = nil;

如果这是准确的,那么是错误的。应该是:

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

不要回复错误以确定失败,检查 BOOL


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

解决方案

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.

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

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