当 UITableView 是 UIView 的子视图时不调用 NSFetchedResultsControllerDelegate 方法(最初加载数据)

Posted

技术标签:

【中文标题】当 UITableView 是 UIView 的子视图时不调用 NSFetchedResultsControllerDelegate 方法(最初加载数据)【英文标题】:NSFetchedResultsControllerDelegate methods not called when UITableView is a subview of UIView (data initially loads) 【发布时间】:2014-03-25 15:09:52 【问题描述】:

我有一个包含UITableViewUIView。这些由继承委托方法UITableViewDelegateNSFetchedResultsControllerDelegateUIViewController 管理。我可以使用NSFetchedResultsController 很好地填充表,但是当对fetchObjects 中的托管对象进行更改时,不会调用委托方法(特别是controllerWillChangeContent)。

我已独立检查对对象进行了更改,并且我已在单元格中反映了这些更改,但是您必须手动重新加载单元格(向上滚动)才能看到更改发生。我正在寻找的行为是,当对对象进行更改(通过保存)时,NSFetchedResultsControllerDelegate 方法会触发,因此我可以对表格视图进行更新。

为了清楚起见,数据是在视图加载时从数据库中填充的,所以我知道代码可以很好地提取数据。

标题界面

@interface HSAwardsViewController : UIViewController <UITableViewDelegate, UITableViewDataSource, NSFetchedResultsControllerDelegate>

@property (nonatomic, retain) IBOutlet UITableView *tableView;

@property (nonatomic, retain) NSPersistentStoreCoordinator *persistentStoreCoordinator;
@property (nonatomic, retain) NSFetchedResultsController *fetchedResultsController;
@property (nonatomic, retain) NSManagedObjectContext *managedObjectContext;

@end

init 方法 - 设置 managedObjectContext(使用 Magical Record)

- (id)initWithCoder:(NSCoder *)aDecoder

    self = [super initWithCoder:aDecoder];
    if (self) 
        HSInternalDB *dbInstance = [HSInternalDB getInternalDB];
        self.persistentStoreCoordinator = [dbInstance getPersistentStoreCoordinator];
        self.managedObjectContext = [NSManagedObjectContext MR_contextWithStoreCoordinator:self.persistentStoreCoordinator];

        self.tableView.delegate = self;
        self.tableView.dataSource = self;

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

设置 NSFetchedResultsController 并分配委托

- (NSFetchedResultsController *)fetchedResultsController 

    if (_fetchedResultsController != nil) 
        return _fetchedResultsController;
    

    NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:@"Award"];

    NSSortDescriptor *sort = [[NSSortDescriptor alloc] initWithKey:@"gameTypeIdentifier" ascending:NO];

    [fetchRequest setSortDescriptors:[NSArray arrayWithObject:sort]];
    [fetchRequest setFetchBatchSize:20];

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

    NSError *error = nil;
    [theFetchedResultsController performFetch:&error];
    theFetchedResultsController.delegate = self;
    self.fetchedResultsController = theFetchedResultsController;

    // Listen for this notification so that the managedObjectContext runs on the main thread
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(contextChanged:) name:NSManagedObjectContextDidSaveNotification object:nil];

    return _fetchedResultsController;




- (void)contextChanged:(NSNotification*)notification

    NSManagedObjectContext *context = [notification object];
    if ([context isEqual:self.managedObjectContext]) 
        return;
    

    if (![NSThread isMainThread]) 
        [self performSelectorOnMainThread:@selector(contextChanged:) withObject:notification waitUntilDone:YES];
        return;
    

    [[self managedObjectContext] mergeChangesFromContextDidSaveNotification:notification];

据我所知,所有连接都是在代码或故事板中建立的。我知道我的数据库中记录了更改,因为我正在监听NSManagedObjectContextDidSaveNotification

这让我很困惑,所以我很感激任何建议或面包屑。如果需要,我很乐意回答任何问题或发布更多代码!

【问题讨论】:

你能解决这个问题吗?我也有类似的问题。 【参考方案1】:

contextChanged: 应该在 MainThread 上调用,因为它涉及 UI 更新。

【讨论】:

是的,我相信我正在确保 if (![NSThread isMainThread]) [self performSelectorOnMainThread:@selector(contextChanged:) withObject:notification waitUntilDone:YES]; return; 是这种情况 你的 managedObjectContext 是否在主线程上改变了?如果没有,它不会触发 frc 委托。 @John 你不知道如果后台线程中的上下文发生变化如何触发委托方法吗?我的意思是我用 NSPrivateQueueConcurrencyType 创建新的上下文,设置父上下文并执行块,我将对象添加到 CoreData。

以上是关于当 UITableView 是 UIView 的子视图时不调用 NSFetchedResultsControllerDelegate 方法(最初加载数据)的主要内容,如果未能解决你的问题,请参考以下文章

当视图消失时,UIView动画停止,重新出现时不再恢复

自定义 UIView 的子视图未出现在 UI 测试中

当 UITableView 枯竭时需要帮助显示自定义 UIView

UITableView,无法识别的选择器发送到实例

当 UIView 的 needsUpdateConstraints 被调用时,UITableview 滚动到顶部[关闭]

UITableView 的子视图与 tableView 的高度不同