【问题标题】:NSNotification concept - what piece of code goes where?NSNotification 概念 - 哪段代码在哪里?
【发布时间】:2011-01-22 16:12:33
【问题描述】:

我的一部分认为我理解 NSNotification 概念。这是一个集中的广播系统,带有基于字符串的通知。在一侧张贴,在另一侧或多侧观察并采取相应行动。不过,我的另一部分,即必须编写代码的部分,每次我需要通知时都会感到困惑。哪些代码进入哪个标头/实现,哪些文件实际进行观察以及如何防止它变得一团糟?是时候把它理顺了,你能帮我验证这些假设吗?我对第 4 名相当有信心,但第 5 名中奖了。


  1. NSNotification 是在 [NSNotification defaultCenter] 的帮助下创建的,不会分配/初始化 NSNotification。正确吗?
  2. 执行 postNofification 壮举的对象总是将self 传递到发布代码:[[NSNotificationCenter defaultCenter] postNotificationName:@"note name" object:self]。正确吗?
  3. 事件冒泡存在于其他语言中,但在带有 NSNotification 的 Objective-C 中不存在。您不传递通知,您使通知名称足够具体以供全球广播使用。正确吗?
  4. 如果您仍想传递对象 A 发布的通知,请在 B 中观察它,处理它并发布一个新的、更具体的通知以供对象 C 观察。例如。 @"MenuItemTapped" 从 A 到 B,@"NavigateTo" 从 B 到 C。对吗?
  5. 通知的名称是一个 NSString。因为张贴者和观察者都希望避免拼写错误,我们将 NSString 常量存储在 [extern const|define|class method|none of the above] 中。你能帮我挑一个吗?
    • 一种尝试是创建类似于NotificationNames.h 的文件,其中包含所有extern NSString *const NOTE_NAME 声明。然而,这会破坏通知的可移植性。
    • 另一个尝试是将 NSNotification 子类化(使用 XCode 模板以保持快速创建),但由于此概念取自 AS3 中的 Event-class 子类,因此看起来非常不客观。还有一个奇怪的问题是你不能在 NSNotification 上调用 [super init],所以事情开始失控了。
    • 我的麻烦来自于繁琐的#import 语句。如何尽量减少拼写错误,同时保持常量/定义的可移植性?

【问题讨论】:

  • 另外,最好从你添加到 NSNotificationCenter 的 dealloc 中的类中删除所有观察者。

标签: objective-c cocoa notifications event-bubbling


【解决方案1】:

你基本上已经明白了。您的数字 1-3 通常是正确的。

  • 您永远不需要分配自己的 NSNotification 对象。
  • 如您所说,您通常将“self”作为通知的“对象”传递,但从概念上讲,如果您“代表”其他事物进行通知,您也可以传递其他内容。但这种情况不太常见。
  • 通知与 UI 中的“事件”不同。可可确实有事件;它们是鼠标/键盘/触摸事件,它们确实通过 UI 对象在“响应者链”中“冒泡”。通知是一种完全独立的机制,与 UI 无关,它通常用于在其他解耦/独立对象之间进行全局广播。这更像是一个对象有多个委托。
  • 是的,您应该在任何使用它的人都能看到的地方定义通知的名称。在 Cocoa 本身中,这通常是一个带有类似 extern NSString *const UIKeyboardDidShowNotification 的声明的公共标头。在一些私有实现文件中是定义。

关于您上面的 #4 的特别说明。将通知视为通知,而不是说明。它们通常捕获状态变化或广泛有趣的事件。 “MenuItemTapped”是一个合理的通知,但“NavigateTo”通常不是,因为这意味着您正在告诉某个特定对象导航到某个地方。如果是这种情况,该对象可能应该是想要导航的事物的委托(或应该是属性),并且您应该直接导致它发生。当然,这不是必需的,您可以根据需要使用该机制。但是 Cocoa 设计模式通常不使用通知来“告诉对象该做什么”,而只使用“告诉谁关心将会/确实发生什么”。有意义吗?

最后,特别是:您在 #4 中的示例——那些听起来像是真正的 UI 事件,并且似乎整个事情都可以通过委托来处理,除非出于某种原因需要对这些对象进行如此解耦。

【讨论】:

  • 对通知名称的通知字符有很好的了解。感谢您提出委托方案。那也应该在列表中。我认为我应该更多地依赖委托而不是通知广播,但是每次我想通知容器对象时创建一个委托协议似乎是一个非常冗长的解决方案。我是不是也不能正确对待代表?
  • 附带说明:在 AS3 中,有一个框架提供了一种替代事件的方法,它介于 AS3 事件和 ObjC 委托之间。它被称为 signals-as3,灵感来自 Qt 中的 C# 事件和信号/插槽。也许在 Objective-C 中也有类似壮举的框架?
  • @Eric-Paul:不幸的是,如果您的对象模型具有重要的层次结构,那么委托可能会变得非常冗长。但是,如果使用得当,它们往往会使代码长期保持良好的可维护性。我对 Qt 或 AS 不熟悉,因此无法在信号/插槽方面为您提供帮助,但我可以说我在旅途中没有遇到任何基本的 Cocoa 附加通知框架。
  • developer.apple.com/library/mac/#documentation/Cocoa/Reference/… 声明“您可以选择任何您喜欢的指定初始化程序”,目的是根据需要继承、分配和初始化您的自定义通知(必须支持名称、对象和用户信息)。
【解决方案2】:
  1. 如果您愿意,可以直接创建 NSNotification 对象。 postNotificationName:object: 只是为您创建、配置和发布通知对象的便捷方法。

  2. 你可以传递任何你喜欢的对象。其目的是允许通知订阅者仅接收有关特定对象的通知,因此理想情况下,您传入通知所涉及的对象,这通常(但不总是)是self

  3. 通知不是事件。它们是应用程序中的全球广播。

  4. 您不会向特定对象发送通知 - 它们是广播。如果您想向特定对象发送消息,只需调用该对象的方法即可。

  5. 头文件中的externs没问题。

【讨论】:

  • 谢谢!你能指定@4 和@5 吗?我不想通过让两个对象互相调用方法来创建依赖循环。我将在哪个标题中存储外部、海报或观察者?唔。当我这样写时,我猜它是海报的标题。
猜你喜欢
  • 2012-12-10
  • 1970-01-01
  • 1970-01-01
  • 2023-03-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-07-19
  • 2012-12-03
相关资源
最近更新 更多