NSNotifications 和 Key-Value Observation 之间的区别主要是耦合之一,但也有性能影响。
任何人都可以订阅您的 NSNotifications。他们只需要知道您通知的字符串/键。他们不需要知道任何关于你的类/对象图等的事情。所以当你想通知一个不知道你的类细节的世界时,NSNotification 是要走的路。例如,如果您要向其他开发人员出售一个框架,那么通过 NSNotification 通知可能比将框架的内部暴露到允许消费者键值对观察您的对象所必需的程度要好。
为了 KVO 观察一个对象,您首先必须能够获得对它的引用,这对于 NSNotifications 来说并不严格(但根据我的经验,这通常是正确的。)其次,您需要足够了解实施知道要观察什么。使用 NSNotification,通知者只需要发布一个通知字符串/密钥。使用 KVO,您需要知道对象的属性名称。当然,有人可以发布静态字符串并告诉你“你可以为这些属性 KVO 我”,但这实际上变成了一个 API 合约,可能更难以维护。 (比如说,例如,你想在未来的版本中删除该属性——然后你必须安装其他东西来继续发送这些通知并在人们调用 valueForKey 时提供值:——简而言之,一旦你这样做了,你永远不能改变那个属性。)
要记住这些不同程度的耦合的另一件事是,使用 KVO,可以期望观察者知道您的类/对象的详细信息。毕竟,他们对您的对象表现出非常特殊的兴趣;他们声称知道这意味着什么——它是如何工作的。因此,您可能希望它们对性能影响敏感。使用 NSNotifications,消费者可以观察到您的通知,几乎对您一无所知,并且可能不知道他们如何响应通知的性能影响。
这两种方法的共同缺点是,如果没有额外的工作,它们都是同步交付的。通知对象受观察者在收到通知时(同步)选择做什么的支配。这两种机制的不同之处在于,对于 NSNotification,通知对象很容易使用 performSelector:afterDelay: 在下一次运行时“异步”发送通知(相对于产生通知的调用)循环(另见 NSNotificationQueue)。这对于 KVO 来说并不容易。在某些情况下,仅此差异可能是至关重要的。
一般来说,我发现 NSNotification 的松散耦合适合于大粒度(即可能代表一大组更改)或相对不频繁的事件。 KVO 通知本质上是细粒度的。您正在明确观察单个对象上单个属性(每个注册)的变化。这有可能会增加注册数量和通知数量。每个观察都有性能成本。
这两者的另一个共同缺点是可调试性。我在上面的评论中提到,KVO 可能是一个调试挑战,它也与 NSNotificationCenter 共享这个挑战。
这两者与委托模式的主要区别在于委托关系通常是 1:1(一个委托)。(当然,您可以拥有一组委托,但这种情况非常少见,并且可能是一种反模式。 ) NSNotification 和 KVO 本质上都是 1:N(许多观察者)。
最后,我总是喜欢说,“使用可以完成工作的最高抽象级别。”如果您只需要 1:1 的关系,请使用委托。对于 1:N 通知,如果 NSNotification 可以工作 - 换句话说,如果所需的耦合很低和/或通知是大粒度的或不频繁的,请使用 NSNotifications。如果耦合很紧密,或者需要细粒度,请使用 KVO。还要记住,您可以通过让委托发送 NSNotifiations 来将委托模式从 1:1 调整为 1:N。使用 NSNotifications 和 KVO,您无法真正控制谁观察您或您有多少观察者。