15

我已经阅读了很多关于 KVO 的文档,但我仍然对何时使用它感到困惑。

如果objA想监视 的某个属性objB,如下所示:

self.objB = [[ObjB alloc] init];
[self.objB addObserver:self
            forKeyPath:@"address"
               options:0
               context:nil];

所以如果objB's 的属性发生变化,并且只能由 改变self,为什么不这样做:

self.objB.property = @"newValue";
[self doSomethingBasedOnNewValueOfObjBnewProperty];

代替

- (void)observeValueForKeyPath:(NSString *)keyPath
                      ofObject:(id)object
                        change:(NSDictionary *)change
                       context:(void *)context

{
    if(keyPath == @"address") {
        [self doSomethingBasedOnNewValueOfObjBnewProperty];
    }
}

当与单例一起使用时,它可能很有用,例如self.objB = [ObjB sharedInstance],其中属性可能会被其他对象更改。这是唯一的用例吗?

4

2 回答 2

18

并非所有类的所有实例都仅由同一实例创建和编辑(这实际上是您的示例所表明的)。

KVO 是一种通用方法,通过该方法一个实例可以观察另一个实例的变化并接收已发生情况的通知。这些变化可以从任何地方触发。

假设您在项目中添加了第 3 方库。你不知道它是如何实现的。调用一种方法可能会更改库类实例中的多个不同属性。KVO 为您提供了一种简单的方法来监控这些变化并做出反应。

KVO 还提供“依赖键”,它允许您配置键之间的关系,因此您可以说“此属性的值取决于另一个对象中的一个或多个其他属性的值”,并且 KVO 会在它发生时告诉您。这在托管对象子类中可能特别有用,例如,如果您有一个临时键保存某个持久键的缓存值,并且每当持久值更改时都需要更新缓存......

于 2013-06-09T08:48:43.717 回答
11

韦恩的回答是完美的。我想通过说明 KVO 可能用途的一些示例来做出贡献。

KVO 在某些对象“说一个或多个视图控制器”需要监视许多对象的变化的情况下很有用。

例如,一个FPS 游戏有一些视图,一个显示玩家之间的交互,一个在角落显示当前玩家得分和健康的视图;当点击按钮或游戏暂停时显示玩家得分的菜单。如果当前玩家击中或被其他玩家击中,则需要更新主视图,通过显示成功击中或显示玩家受伤的迹象,得分和健康视图需要更新其数据和玩家的得分视图需要更新。现在假设您需要添加一个新的控制器对象来监控玩家的成就通过监控他的分数和他的杀戮次数。该对象还需要收到有关玩家发生的任何事件的通知。

在那种情况下,许多对象需要监视许多其他对象“当前玩家和其他玩家”的变化。KVO 为您提供了一个简单的工具来实现这一点,而无需编写代码来处理通知注册和实际通知。想一想您将如何从头开始实施它以注意到差异。


在另一个示例中,我通常倾向于为Web 服务检索到的一些数据创建一个单例加载器。在这种情况下,应用程序的许多部分都需要一些数据。

例如,您想开发一个由商店制作的应用程序,向用户显示可用商品。这个应用程序需要向用户显示一个显示所有项目的表格视图,一个显示特定类别项目的视图,另一个显示销售项目的视图,另一个显示某个项目的详细信息和可用数量的视图。现在假设应用程序需要每隔几个小时或在用户请求刷新时刷新数据。该加载器类可以自己处理刷新操作,并且视图控制器可以注册到相关键。这样,刷新在一个对象中处理,其他对象可以只专注于它们的视图处理逻辑。

于 2013-06-09T10:35:00.867 回答