带有 fetchedResultsController 的 Tableview 在应用重新启动或视图重新加载之前不会更新新内容

Posted

技术标签:

【中文标题】带有 fetchedResultsController 的 Tableview 在应用重新启动或视图重新加载之前不会更新新内容【英文标题】:Tableview with fetchedResultsController not updating new content until app restart or view gets reloaded 【发布时间】:2015-01-16 07:42:31 【问题描述】:

在应用程序重新启动或我转到另一个视图控制器并返回之前,我的 tableview 不会被 nsfetchedresultscontroller 中的数据填充。我以前从来没有遇到过这个问题,很奇怪。

代码:

- (void)viewDidLoad 
    [super viewDidLoad];

    self.tableView.contentInset = UIEdgeInsetsMake(0, 0, 60, 0);

    [super viewDidLoad];


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


    UIRefreshControl *refresh = [[UIRefreshControl alloc] init];
    [refresh addTarget:self
                action:@selector(refresh)
      forControlEvents:UIControlEventValueChanged];
    self.refreshControl = refresh;

    UITableViewController *tableVC = [[UITableViewController alloc]initWithStyle:UITableViewStylePlain];
    [tableVC setTableView:self.tableView];
    tableVC.refreshControl = self.refreshControl;

    [self.tableView setContentOffset:CGPointMake(0.0f, -60.0f)
                                          animated:YES];
    [self getPosts];


    // Do any additional setup after loading the view.

getPosts 为 tableview 拉入所有帖子并将它们保存到 coredata。

-(void)getPosts

    [self.refreshControl beginRefreshing];
    [self.postsController getPostsFeedWithCompletion:^(BOOL complete, NSArray *posts) 
        [self.refreshControl endRefreshing];
     failure:^(NSString *message) 
        [self.refreshControl endRefreshing];
        ALAlertBanner *alert = [ALAlertBanner alertBannerForView:self.view
                                                           style:ALAlertBannerStyleFailure
                                                        position:ALAlertBannerPositionTop
                                                           title:@"Error"
                                                        subtitle:@"Error retrieving posts, please try again."];
        [alert show];

    ];

getPostsFeedWithCompletion 方法:

-(void)getPostsFeedWithCompletion:(void (^)(BOOL complete, NSArray *posts))complete
                          failure:(void (^)(NSString *message))failure


    [[APIManager sharedManager] getPath:@"posts/feed"
                             parameters:nil
                                success:^(AFHTTPRequestOperation *operation, id responseObject) 
                                    DLog(@"response: %@", responseObject);

                                    NSArray __block *posts;

                                    [MagicalRecord saveWithBlock:^(NSManagedObjectContext *localContext)
                                        posts = [self createPosts:responseObject[@"posts"] inContext:localContext];
                                     completion:^(BOOL success, NSError *error) 
                                        if(complete)
                                            complete(YES, posts);
                                        
                                    ];

                                
                                failure:^(AFHTTPRequestOperation *operation, NSError *error) 
                                    DLog(@"error: %@", error);
                                    if(failure)
                                        failure(@"Error retrieving posts");
                                    
                                ];

这里是 nsfetchedresultscontroller 实例化

- (NSFetchedResultsController *)fetchedResultsController 

    if (_fetchedResultsController != nil) 
        return _fetchedResultsController;
    

    NSManagedObjectContext *context = [NSManagedObjectContext MR_contextForCurrentThread];

    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
    NSEntityDescription *entity = [NSEntityDescription
                                   entityForName:@"Post" inManagedObjectContext:context];
    [fetchRequest setEntity:entity];

    NSArray  *following = [[SessionManager getInstance].currentLoggedInUser.follows allObjects];

    NSMutableArray *predicateArray = [NSMutableArray array];
    NSDate *now = [NSDate date];

    [predicateArray addObject:[NSPredicate predicateWithFormat:@"account IN %@", following]];
    [predicateArray addObject:[NSPredicate predicateWithFormat:@"expiration > %@", now]];

    NSCompoundPredicate *filterPredicate = [NSCompoundPredicate andPredicateWithSubpredicates:predicateArray];
    [fetchRequest setPredicate:filterPredicate];
    [fetchRequest setFetchBatchSize:20];


    NSSortDescriptor *sort = [[NSSortDescriptor alloc]
                              initWithKey:@"expiration" ascending:YES];
    [fetchRequest setSortDescriptors:[NSArray arrayWithObject:sort]];

    [fetchRequest setFetchBatchSize:20];

    NSFetchedResultsController *theFetchedResultsController =
    [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest
                                        managedObjectContext:context
                                          sectionNameKeyPath:nil
                                                   cacheName:nil];
    self.fetchedResultsController = theFetchedResultsController;
    _fetchedResultsController.delegate = self;

    return _fetchedResultsController;


这是 MagicalRecord 保存的日志:

[NSManagedObjectContext(MagicalSaves) MR_saveWithOptions:completion:](0x7ffcea601bd0) → Saving <NSManagedObjectContext (0x7ffcea601bd0): *** UNNAMED ***> on *** BACKGROUND THREAD ***
[NSManagedObjectContext(MagicalSaves) MR_saveWithOptions:completion:](0x7ffcea601bd0) → Save Parents? 1
[NSManagedObjectContext(MagicalSaves) MR_saveWithOptions:completion:](0x7ffcea601bd0) → Save Synchronously? 1
[NSManagedObjectContext(MagicalRecord) MR_contextWillSave:](0x7ffcea601bd0) Context UNNAMED is about to save. Obtaining permanent IDs for new 22 inserted objects
[NSManagedObjectContext(MagicalSaves) MR_saveWithOptions:completion:](0x7ffceba008f0) → Saving <NSManagedObjectContext (0x7ffceba008f0): *** DEFAULT ***> on *** BACKGROUND THREAD ***
[NSManagedObjectContext(MagicalSaves) MR_saveWithOptions:completion:](0x7ffceba008f0) → Save Parents? 1
[NSManagedObjectContext(MagicalSaves) MR_saveWithOptions:completion:](0x7ffceba008f0) → Save Synchronously? 1
[NSManagedObjectContext(MagicalRecord) MR_contextWillSave:](0x7ffceba008f0) Context DEFAULT is about to save. Obtaining permanent IDs for new 22 inserted objects
[NSManagedObjectContext(MagicalSaves) MR_saveWithOptions:completion:](0x7ffcea746c10) → Saving <NSManagedObjectContext (0x7ffcea746c10): *** BACKGROUND SAVING (ROOT) ***> on *** MAIN THREAD ***
[NSManagedObjectContext(MagicalSaves) MR_saveWithOptions:completion:](0x7ffcea746c10) → Save Parents? 1
[NSManagedObjectContext(MagicalSaves) MR_saveWithOptions:completion:](0x7ffcea746c10) → Save Synchronously? 1
[NSManagedObjectContext(MagicalRecord) MR_contextWillSave:](0x7ffcea746c10) Context BACKGROUND SAVING (ROOT) is about to save. Obtaining permanent IDs for new 22 inserted objects
_70-[NSManagedObjectContext(MagicalSaves) MR_saveWithOptions:completion:]_block_invoke21(0x7ffcea746c10) → Finished saving: <NSManagedObjectContext (0x7ffcea746c10): *** BACKGROUND SAVING (ROOT) ***> on *** MAIN THREAD ***

【问题讨论】:

我的猜测:您将数据保存在后台托管对象上下文中并且不将它们合并到主线程的上下文中? @MichałCiuba 我正在后台线程上创建数据,但使用 [context MR_saveToPersistentStoreAndWait] 进行保存,这是我做过一千次但从未遇到过这个问题的方法 我不熟悉 MagicalRecord,但这会导致将数据合并到主线程的上下文中吗? NSFRC 使用该上下文。你实现NSFetchedResultsControllerDelegate 方法了吗?还有,这些行是干什么用的:UITableViewController *tableVC = [[UITableViewController alloc]initWithStyle:UITableViewStylePlain]; [tableVC setTableView:self.tableView];?据我所知,两个控制器不能共享他们的视图。 @MichałCiuba 它不是一个 tableviewcontroller 它是一个带有 tableview 的 uiviewcontroller。该代码添加了刷新控件 看起来根本没有调用任何 NSFetchedResultsController 委托方法。 【参考方案1】:

原来是我的谓词有问题。 NSArray *following 在 FRC 的 getter 中被硬设置,但在 getPosts api 调用完成之前它是空的。

【讨论】:

以上是关于带有 fetchedResultsController 的 Tableview 在应用重新启动或视图重新加载之前不会更新新内容的主要内容,如果未能解决你的问题,请参考以下文章

fetchedResultsController 获取带有谓词的实体的最佳实践

iOS:表视图(带有 FetchedResultsController)作为另一个视图的子视图

带有 fetchedResultsController 的 Tableview 在应用重新启动或视图重新加载之前不会更新新内容

CoreData:带有子主上下文的私有上下文 - FetchedResultsController 未获得更新

fetchedResultsController fetchedObjects 返回一个 NSCFString 而不是 NSArray

可可 iphone fetchedResultsController 排序