【问题标题】:How be notified only when CoreData object(s) change?仅当 Core Data 对象)更改时如何通知?
【发布时间】:2017-02-16 20:34:45
【问题描述】:

每次与服务器同步时,我都会刷新我的 CoreData 对象的所有字段。

即使没有任何变化,我仍然会在代码的其他地方收到NSManagedObjectContextObjectsDidChangeNotification

  • 这是预期的行为吗?
  • 如何防止这种情况发生并且仅在实际发生更改时才收到通知?

当我在刷新对象后添加下面的代码时,事情会按我的意愿工作。但是为什么 CoreData 不能解决这个问题呢?

if (object.changedValues.count == 0)
{
    [object.managedObjectContext refreshObject:object mergeChanges:NO];
}

【问题讨论】:

    标签: ios core-data


    【解决方案1】:
    • 是的,即使值没有改变,新的写入仍在托管对象上下文中发生。所以,NSManagedObjectContextObjectsDidChangeNotification 预计会被解雇。

    考虑将NSFetchedResultsController 用作:

    @interface CoreDataHelper : NSObject < NSFetchedResultsControllerDelegate >
    
    @property (nonatomic, readonly) NSManagedObjectContext *context;
    
    + (instancetype)sharedInstance;
    
    @end
    
    @implementation
    @synthesize context = _context;
    
    + (instancetype)sharedInstance{
        static dispatch_once_t once;
        static CoreDataHelper *sharedInstance;
        dispatch_once(&once, ^{
            sharedInstance = [self new];
        });
        return sharedInstance;
    }
    
    - (NSManagedObjectContext *)context{
    
        if (_context != nil) {
            return _context;
        }
    
        NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator]; // you know what goes in PSC here, right?
        if (!coordinator) {
            NSLOG(@"Argh! coordinator == nil");
            return nil;
        }
    
        _context = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
        [_context setPersistentStoreCoordinator:coordinator];
        return _context;
    }
    
    - (void)controllerDidChangeContent:(NSFetchedResultsController *)controller{
    /*
    This function will be invoked by the OS whenever a Managed Object changes.
    Keep in mind that this will be invoked on the Managed Object Context Queue.
    This is the place where your logic to be performed whenever a object changes needs to be.
    */
    }
    
    @end
    

    // 现在在你的文件中

    NSFetchedResultsController *fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:[CoreDataHelper sharedInstance].context sectionNameKeyPath:nil cacheName:nil];
    
    fetchedResultsController.delegate = [CoreDataHelper sharedInstance];
    
    NSError *error;
    if (![fetchedResultsController performFetch:&error]){
        NSLOG(@"fetch error %@", error);
    }
    

    现在,由于我们已将self 连接为fetchedResultsController 的代表,self 需要符合NSFetchedResultsControllerDelegate 协议。
    您选择覆盖任何可选方法,最直接的方法是:
    - (void)controllerDidChangeContent:(NSFetchedResultsController *)controller

    【讨论】:

    • 感谢您的努力,但不涉及视图控制器,因此这对我没有帮助。除了在每个对象上测试changedValues 并丢弃未更改的内容之外,没有其他方法可以避免通知吗?
    • 好吧,self 可以是 NSObject 类的任何实例,不一定(甚至通常)是 UIViewController。你可以有一个 Core Data Helper 单例或者一个简单的类实例,比如@interface CoreDataHelper : NSObject
    • 我放弃了:你仍然显示NSFetchedResultsController,而你只是写the magic of db updates,但这是我唯一的问题。所以这是一堆无用的代码,没有答案。
    • @meaning-matters controllerDidChangeContent: 将在任何托管对象更改时被调用。此时,您可以执行要执行的操作,即您在收听NSManagedObjectContextObjectsDidChangeNotification时执行的操作@
    • 您的controllerDidChangeContent 是否仅用于真正的更改,而不用于未更改任何字段的CoreData 对象更新?如果是,请解释原因。
    猜你喜欢
    • 1970-01-01
    • 2013-05-01
    • 1970-01-01
    • 1970-01-01
    • 2012-05-21
    • 1970-01-01
    • 1970-01-01
    • 2015-01-12
    • 1970-01-01
    相关资源
    最近更新 更多