我有两个NSManagedObject子类:Parent和Child。 Parent在OrderedSet中包含许多Child(ren)。当孩子的状态发生变化时,我希望父母知道它。
如果我使用其他语言进行编程,我可能会使用事件,让父母监听每个孩子的事件,但是鉴于目标操作仅限于查看组件,所有Objective C为我提供的是使用全局NSNotificationCenter 。我绝对不喜欢使用模型进入全局通知的想法(直接通过事件直接收听我的书中的确定),所以看来我唯一的选择是委托。然而,在两个NSManagedObjects之间使用委托似乎是一个危险的想法,因为很难确保一方不会丢失对另一方的引用。
有没有人对我应该如何处理这个问题有任何建议?
答案 0 :(得分:2)
另一种选择是键值观察。设置如下:
const static void *kParentObservingChildSomePropertyContext = &kParentObservingChildSomePropertyContext;
[child addObserver: child.parent forKeyPath: @"someProperty" options: /*see below*/ context: kParentObservingChildSomePropertyContext];
存在奇怪的常量定义,因为每个观察上下文都应该是唯一的,这样您就不会使用超类或子类观察上下文。要查看您需要设置哪些选项,consult the manual并与您的具体需求进行比较。现在,只要您的子对象上的该属性发生更改,您的父级将会收到:
-(void)observeValueForKeyPath: (NSString *)path ofObject: (id)object change: (NSDictionary *)change context: (void *)context;
检查 观察的正确上下文,然后处理更改。如果您在此处获得了不同的上下文,请将邮件转发至super
。
当您完成观察路径时,您将父项删除为子项的观察者:
[child removeObserver: child.parent forKeyPath: @"someProperty" context: kParentObservingChildSomePropertyContext];
使用您在-addObserver:forKeyPath:options:context
中使用的相同上下文指针,以便删除正确的观察实例。
然而,在两个NSManagedObjects之间使用委托似乎是一个危险的想法,因为很难确保一方不会丢失对另一方的引用。
委派,观察和观察来自特定对象的通知都会遇到此问题。您需要确保您对通知感兴趣的生命周期与所涉及对象的生命周期相匹配,否则您可能很容易“泄漏”观察信息或 - 这更糟糕 - 将通知发送到过时的对象指针。这些解决方案都不具备此功能,但在Delegate模式的情况下,您可以使用归零弱引用来确保当父对象消失时,子进程将不再尝试委托给它。
答案 1 :(得分:1)
我在视图控制器中选择要监视的字段,以便为请求提供服务... [self addObserver:self forKeyPath:@“clientProgress.dateLastUpdated”options:0 context:nil];
我确保在同一个视图控制器中我删除了dealloc上的观察者(或者在ARC中的dealloc的任何传递)。 - (void)dealloc { [self removeObserver:self forKeyPath:@“clientProgress.dateLastUpdated”]; }
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
if ([keyPath isEqual:@"clientProgress.dateLastUpdated"]) {
// If this key path has changed, the browser needs to update its display.
NSError *error = nil;
if (![managedObjectContext save:&error]) {
UIAlertView *dialog = [[UIAlertView alloc] initWithTitle:@"Save Error" message:@"Error saving inserted record, contact Tech Support" delegate:self cancelButtonTitle:@"Ok" otherButtonTitles:nil];
[dialog show];
[dialog release];
exit(-1); // Fail
}
if ( changeIsComingFromLibraryInsert ) {
}
[conditioningTableView reloadData];
}
// Essential to call super class implementation - NSArrayController relies heavily on KVO
//[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
}
最后,当我想给观察者打电话时,我只是更新日期...... //通过设置修改日期和前面的ViewController强制保存,然后从调用视图控制器保存并重新加载 //因为有一个观察者正在观看这个关键值 clientProgress.dateLastUpdated = [NSDate date];