如何为NSManagedObject执行完美的KVO?

7

完美的KVO包括两个部分:正确添加观察者和正确删除观察者。

故事背景:

  1. 我使用一个UITableViewCell(cell)来显示一个NSManagedObject(object)。
  2. 每个对象都有一些需要被其cell观察的动态属性。
  3. 并非所有对象都具有相同的观察属性。我像这样有选择地添加关键路径观察者:

    if (object.thumbnail_pic_url) [object addObserver:cell forKeyPath:@"thumbnail_picture" options:0 context:NULL];

  4. 对象可能被删除。当对象被删除时,我必须删除观察者。由于数据库非常大且复杂,因此我绝对不想注册所有单元格以接收moc通知,如NSManagedObjectContextObjectsDidChangeNotification。但是如果必须这样做,我可以接受在对象中添加一个cell ivar,即使这违反了良好的模型-视图-控制器设计模式。

问题:当对象被删除时,我如何正确地为所有已注册的关键路径从对象中删除观察者(cell)?

实际上,这是一个可以分成两个小问题的大问题:

  1. 哪里是放置观察者移除代码的最佳位置?
  2. 如何确定要注销哪些关键路径?在删除对象后,我无法查询其属性——这将导致无法满足的错误,因此我无法编写以下代码:

    if (object.thumbnail_pic_url) [object removeObserver:cell forKeyPath:@"thumbnail_picture"];

我也不能盲目地为未注册的关键路径删除观察者——会引发异常(Cannot remove an observer for the key path "thumbnail_picture" from because it is not registered as an observer.)。


作为一个建议,你尝试使用fetchedResultsController来管理tableview的更新了吗? - Rog
谢谢@Rog。当然我在使用它。你是指在NSFetchedResultsControllerDelegate方法中执行KVO注销吗?这是一种可能的方式。但是当我收到委托调用时,对象已经被删除了,不是吗?那么它无法解决要注销哪些关键路径的问题。 - an0
3个回答

3

an0,

有一个专门用于执行计时删除的NSManagedObject方法:-prepareForDeletion。

它的文档声称:“您可以实现此方法,在对象被删除之前执行任何所需的操作,例如在关系被拆除之前进行自定义传播或使用键值观察重新配置对象。”

您还可以查看-willTurnIntoFault和-didTurnIntoFault。但我认为您会更喜欢使用-prepareForDeletion。

安德鲁

附言:这个方法在类参考中有记录。我恭敬地建议您通过阅读文档来节省时间。


@Andrew,谢谢。我找到并使用了-prepareForDeletion方法。但是我仍然需要通知cell对象该对象即将死亡,以便取消注册KVO。虽然不太美观,但它能用 :) - an0

0
实现 KVO 的主要问题在于你不知道对象何时被删除,至少在 NSManagedObject 子类之外无法得知。你可以创建一个 NSManagedObject 的子类并覆盖其 didChangeValueForKey: 方法,从而在其中创建一个通用委托来解决这个问题。
  // DataObservingManagedObject.h

  #import <Foundation/Foundation.h>
  #import <MMRecord/MMRecord.h>

  @protocol DataObservingDelegate <NSObject>

  -(void)valueChangedForKey:(NSString*)key andValue:(id)value;
  @end

  @interface DataObservingManagedObject : NSManagedObject

  @property(nonatomic,weak)id<UserStatusDelegate> changeDelegate;

  @end

  //DateObservingManagedObject.m

  #import "DateObservingManagedObject.h"

  @implementation DateObservingManagedObject

  @synthesize changeDelegate=_changeDelegate;


  -(void)didChangeValueForKey:(NSString *)key{
    [self.changeDelegate valueChangedForKey:key andValue:[self valueForKey:key]];
  }

  @end

2
小心,苹果的文档中明确表示不可以覆盖重写-(void)didChangeValueForKey方法。 - GOrozco58

0

我相信错误出在步骤1。单元格应该被设计成显示不同的对象。单元格只是带标签的视图,可以显示任何东西。表格被优化以重用相同的单元格来展示不同的数据对象。在你的VC中创建configureCellWithEvent、configureCellWithVenue等方法,然后你可以从通用标识符队列中请求一个单元格,并将其传递给这些方法。然后你可能甚至不需要考虑何时添加或删除观察者,因为单元格不应该有对象观察者。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接