持久存储更改后如何刷新 fetchedResultsController

Posted

技术标签:

【中文标题】持久存储更改后如何刷新 fetchedResultsController【英文标题】:how to refresh fetchedResultsController after persistent store change 【发布时间】:2014-10-21 04:13:36 【问题描述】:

在编程方面我是一个周末战士,所以我可能做错了什么......

我有一个拆分视图控制器、核心数据、nsfetchedResultsController,一切都很好。我现在可以选择让用户创建persistentStore.sqlite 文件的备份文件。当用户从备份文件恢复时,tableview 不会反映任何更改。最重要的是,从那时起,无法从 tableview 添加/删除进行任何持久的更改。当我退出应用程序并重新启动它时,所有数据都在备份中,并且一切正常。

如何强制 tableview 从 fetched results 控制器获取现在的新信息?或者我如何强制

以下是我迄今为止尝试过的一些零散的尝试:

MasterViewController.m

- (void)viewDidLoad

    context = [[OSCDStackManager sharedManager] managedObjectContext];


[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(reloadFetchedResults) name:OSFilesUpdatedNotification object:nil];

- (void)reloadFetchedResults:(NSNotification*)note 
    NSError *error = nil;
    if (![[self fetchedResultsController] performFetch:&error]) 
        NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
        abort();
    
    if (note) 
        [self.tableView reloadData];
    



- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller

    NSError *error = nil;
    [self.fetchedResultsController performFetch:&error];
    [self.tableView endUpdates];
    [self.tableView reloadData];

来自 tableview 上的手动刷新下拉...

-(void) updateTable
    context = [[OSCDStackManager sharedManager] managedObjectContext];
    NSError *error = nil;
    [self.fetchedResultsController performFetch:&error];
    //[self.tableView endUpdates];
    [self.tableView reloadData];
    [self.refreshControl endRefreshing];


- (void)viewWillAppear:(BOOL)animated  
    [self.tableView reloadData];



- (NSFetchedResultsController *)fetchedResultsController

    context = [[OSCDStackManager sharedManager] managedObjectContext];
    if (_fetchedResultsController != nil) 
        return _fetchedResultsController;
    
    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
    NSEntityDescription *entity = [NSEntityDescription entityForName:@"Event" inManagedObjectContext:context];
    [fetchRequest setEntity:entity];
    [fetchRequest setFetchBatchSize:20];
    NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"name" ascending:YES];
    NSArray *sortDescriptors = @[sortDescriptor];
    [fetchRequest setSortDescriptors:sortDescriptors];
    NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:context sectionNameKeyPath:nil cacheName:nil];
    //[NSFetchedResultsController deleteCacheWithName:@"cache"];
    aFetchedResultsController.delegate = self;
    self.fetchedResultsController = aFetchedResultsController;
    NSError *error = nil;
    if (![self.fetchedResultsController performFetch:&error]) 
        NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
        abort();
    
    return _fetchedResultsController;
 

即使这是我邻居的应用程序,我也不想告诉他在备份后杀死并重新启动应用程序...

解决方案最终成为以下两个答案的组合,

- (void)reloadFetchedResults
    self.fetchedResultsController = nil;
    [NSFetchedResultsController deleteCacheWithName:@"cache"];
    NSError *error = nil;
    if (![self.fetchedResultsController performFetch:&error]) 
        NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
        abort();
    
    [self.tableView reloadData];

【问题讨论】:

【参考方案1】:

你删除缓存了吗?

您需要先将缓存名称设置为fetchedResultsController(注意末尾的cacheName 参数):

_fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:query
                                                                managedObjectContext:context
                                                                  sectionNameKeyPath:nil
                                                                           cacheName:@"CACHE_NAME"];

然后在进行更新时删除缓存:

[NSFetchedResultsController deleteCacheWithName:@"CACHE_NAME"];

执行此操作后,通过执行此操作再次从核心数据加载:

NSError *error;
if (![self.fetchedResultsController performFetch:&error]) 
    // Update to handle the error appropriately.
    NSLog(@"Unresolved error loading data %@, %@", error, [error userInfo]);
    exit(-1);  // Fail

[self.tableView reloadData];

【讨论】:

【参考方案2】:

消除你的 FRC

-(void)reloadData

    NSError *error = nil;
    self.fetchedResultsController = nil;

    if (![self.fetchedResultsController performFetch:&error]) 

        NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
    
    else
        [self.tableView reloadData];


** 编辑 ** 如果前面的“自我”不明显,你需要在课堂上的某个地方

-(NSFetchedResultsController *)fetchedResultsController

    if (!_fetchedResultsController)
    
        _fetchedResultsController = [NSFetchedResultsController alloc]initWithFetchRequest:aFetchRequest
                                         managedObjectContext:aManagedObjectContext // the main thread MOC
                                           sectionNameKeyPath:nil cacheName:nil];
            // addional FRC setup etc.

    

    return _fetchedResultsController;

【讨论】:

这个终于解决了,但我还需要删除缓存。 您必须将nil 出您的NSFetchedResultsController 吗?我从来没有这样做过。我只需要删除缓存。 这个例子也是错误的,你设置self.fetchedResultsController = nil但是你在下一行使用它。 @Evils 我认为说这是错误的不公平......问题是'如何在持久存储更改后刷新 fetchedResultsController' 清除缓存也可以。但你可以拥有sectionNameKeyPath:nil cacheName:nil]' 惰性对象相当普遍......它应该是 Obj C 和 Swift 的第二天性 这是一个了不起的提示!我不知道你必须取消它。没有“无效”电话或类似电话。谢谢,@Magoo!【参考方案3】:

如果您要替换 sqlite 文件,您可能最好将所有内容都拆掉并从新的托管对象上下文开始。这是与删除商店类似的问题。

【讨论】:

以上是关于持久存储更改后如何刷新 fetchedResultsController的主要内容,如果未能解决你的问题,请参考以下文章

Vuex 刷新页面后数据就消失了,怎么保存数据持久化?

SwiftUI 试图从 FetchedResults 获取对象但没有找到方法

由于事件导致模型更改后AngularJS不刷新视图

如何在 Actor 中持久化消息并在失败后回复(JVM 崩溃)?

CloudKit:如何使用本地持久存储处理帐户更改?

如何实现持久(非刷新)页面元素?