1

我有两个 NSManagedObject 子类:Parent 和 Child。Parent 在 OrderedSet 中包含许多 Child(ren)。当孩子的状态发生变化时,我希望父母知道它。

如果我用另一种语言编程,我可能会使用事件,让父级监听来自其每个子级的事件,但是鉴于目标操作仅限于查看组件,所有 Objective C 提供给我的是使用全局 NSNotificationCenter。我绝对不喜欢模型利用全局通知的想法(在我的书中直接通过事件收听是可以的),所以看来我唯一的选择是委派。然而,在两个 NSManagedObjects 之间使用委托似乎是一个危险的想法,因为很难确保一方不会失去对另一方的引用。

有人对我应该如何处理这个有任何建议吗?

4

2 回答 2

2

另一种选择是键值观察。像这样设置它:

const static void *kParentObservingChildSomePropertyContext = &kParentObservingChildSomePropertyContext;

[child addObserver: child.parent forKeyPath: @"someProperty" options: /*see below*/ context: kParentObservingChildSomePropertyContext];

存在奇怪的常量定义是因为每个观察上下文都应该是唯一的,这样您就不会踩到超类或子类观察上下文。要查看需要设置的选项,请查阅手册并与您的特定需求进行比较。现在,每当您的子对象上的该属性发生更改时,您的父级将收到:

-(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 之间使用委托似乎是一个危险的想法,因为很难确保一方不会失去对另一方的引用。

委托、观察和监视来自特定对象的通知都存在这个问题。您需要确保您对通知感兴趣的生命周期与所涉及对象的生命周期相匹配,否则您可能很容易“泄漏”观察信息,或者 - 更糟糕的是 - 将通知发送到陈旧的对象指针。这些解决方案都不能对此免疫,尽管在委托模式的情况下,您可以使用归零弱引用来确保当父对象消失时,子对象将不再尝试委托给它。

于 2012-05-27T12:08:13.177 回答
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];

于 2012-05-27T12:53:10.097 回答