19

在我的模型中,我有一组称为事件的对象。我希望每当将新对象添加到事件时通知我的控制器。

我认为这样做的一个好方法是使用 KVO 模式在事件发生变化时得到通知(从添加的新对象)

// AppDelegate
// events is a NSMutableArray @property/@synthesize etc...

[appDelagate addObserver:self
               forKeyPath:@"events"
                  options:NSKeyValueObservingOptionNew
                  context:NULL];

但是没有调用observeValueForKeyPath方法,我发现数组不符合 KVO :-(

一种选择是通过为 keyPath调用willChangeValueForKey来手动触发该方法

// ViewController
[self willChangeValueForKey:@"events"];
[self.events addObject:event];
[self didChangeValueForKey:@"events"];

但这感觉很重,因为我可能还应该跟踪事件数组的前后状态,以便可以从observeValueForKeyPath方法访问它。

一种方法是使用标准数组(而不是可变数组)并在每次我想添加一个新对象时创建/设置一个新的事件实例,或者我可以创建一个单独的属性来跟踪有多少项目在可变数组(我希望你能观察到 @"events.count" )。

另一种选择是使用 NSNotificationCenter。我还阅读了一些建议使用块的答案(但我不知道从哪里开始)。

最后,我可以在我的委托中保留我的控制器实例并发送相关消息吗?

// Delegate
[myController eventsDidChange];

保留委托对控制器的引用是否很奇怪?

我正在努力了解如何选择最佳使用方法,因此非常感谢任何有关性能、未来代码灵活性和最佳实践的建议!

4

2 回答 2

18

您不应该为可变集合创建直接的公共属性,以避免它们在您不知情的情况下发生变异。NSArray本身不是可观察的键值对,但您的一对多属性 @"events"是。以下是如何观察它:

首先,为不可变集合声明一个公共属性:

@interface Model
@property (nonatomic, copy) NSArray *events;
@end

然后在你的实现中用一个可变的 ivar 支持它:

@interface Model ()
{
    NSMutableArray *_events;
}
@end

并覆盖 getter 和 setter:

@implementation Model

@synthesize events = _events;

- (NSArray *)events
{
    return [_events copy];
}

- (void)setEvents:(NSArray *)events
{
    if ([_events isEqualToArray:events] == NO)
    {
        _events = [events mutableCopy];
    }
}

@end

如果其他对象需要给你的模型添加事件,他们可以通过调用-[Model mutableArrayValueForKey:@"events"].

NSMutableArray *events = [modelInstance mutableArrayValueForKey:@"events"];
[events addObject:newEvent];

这将通过每次使用新集合设置属性来触发 KVO 通知。为了获得更好的性能和更精细的控制,请实现其余的数组访问器

另请参阅:观察 NSMutableArray 以进行插入/删除

于 2012-05-03T17:39:00.250 回答
0

根据访问器方法的文档,您应该实现:

- (void)addEventsObject:(Event*)e
{
    [_events addObject:e];
}

- (void)removeEventsObject:(Event*)e
{
    [_events removeObject:e];
}

然后 KVO 将在调用这些通知时触发通知。

于 2015-03-20T23:34:02.570 回答