【问题标题】:Observing Changes to a mutable array using KVO vs. NSNotificationCenter使用 KVO 与 NSNotificationCenter 观察对可变数组的更改
【发布时间】:2012-05-13 06:02:31
【问题描述】:

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

我认为这样做的一个好方法是使用 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];

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

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

【问题讨论】:

    标签: ios model-view-controller delegates key-value-observing nsnotificationcenter


    【解决方案1】:

    您不应该为可变集合创建直接的公共属性,以避免它们在您不知情的情况下发生变异。 NSArray 本身不是可观察的键值对,但您的一对多 property @"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 通知。要获得更好的性能和更精细的控制,请实现 array accessors 的其余部分。

    另请参阅:Observing an NSMutableArray for insertion/removal。

    【讨论】:

    • 谢谢! mutableArrayValueForKey 可以解决问题。当您想在模型与控制器之间进行通信时,您对如何选择使用哪种模式(KVO、NotificationCenter、委托)有什么建议吗?
    • 我肯定在这里遗漏了一些东西。如果有人要添加或插入对象:atIndex:一个对象到支持可变数组,有人可以解释一下 setEvents 会在哪里被调用吗?
    【解决方案2】:

    根据docs on accessor methods,您应该实施:

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-01-03
      • 1970-01-01
      • 1970-01-01
      • 2019-09-09
      • 1970-01-01
      • 1970-01-01
      • 2019-02-12
      • 2012-04-20
      相关资源
      最近更新 更多