LRNotificationObserver 是一种更智能、更简单、更好的使用 NSNotificationCenter 的方法,它使用了 RAII。
NSNotificationCenter 的典型使用是一个两步过程
注册一个特定的通知。
[[NSNotificationCenter defaultCenter] addObserver:anObserver
selector:@selector(handleNotification:)
name:aNotificationName
object:anObjectThatFiresTheNotification];
从它注销。
[[NSNotificationCenter defaultCenter] removeObserver:anObserver
name:aNotificationName
object:anObjectThatFiresTheNotification];
你也可以注销观察者可能已注册的任何通知。
[[NSNotificationCenter defaultCenter] removeObserver:self];
当在一个 UIViewController 子类中使用此代码时,我们通常在 init、viewDidLoad 或 view(Will/Did)Appear 中放置订阅代码,在 dealloc、viewDidUnload 或 view(Will/Did)Disappear 中放置注销代码。确保在 dealloc 中一次性注销所有通知,除非你还要注销父类可能已订阅的所有通知。这是 UIViewControllers 中的一个典型问题,当你不小心在 viewDidDisappear 中注销所有通知时,你将停止接收旋转事件。经验法则:只注销你明确订阅的通知...
这个 API 有两个主要问题
在 NSNotificationCenter 最常见的使用中,当观察者死亡时,我们将注销所有通知,这意味着我们必须重写 dealloc 以放置注销代码。在 ARC 中,如果我们不需要这样做,那就更好了。
我们只能提供一个选择器,而不能提供块。
是的,这不算什么大问题,这并不是一个像 KVO 那样糟糕的 API,但仍然让人烦恼。
第二个问题在 Apple 引入的语言块(iOS 4 和 Mac OS X 10.6)中得到了解决。听通知的新方法不 像有些人所说的那样有害。
id observer = [[NSNotificationCenter defaultCenter] addObserverForName:UIApplicationDidReceiveMemoryWarningNotification
object:nil
queue:[NSOperationQueue mainQueue]
usingBlock:^(NSNotification *note) {
// Handle notification
}];
这个新 API 的真正问题是最多人误解了它。它返回一个匿名对象(观察者),必须保存以在需要时注销。
[[NSNotificationCenter defaultCenter] removeObserver:observer];
这使我们不仅要保存该观察者在我们的类中,还要重写 dealloc 并从通知中心移除它。
所以,当 Apple 引入了这个新 API...为什么不使用 RAII 并让这个新的观察者在它死亡时注销通知?为什么要让我们存储这个对象以稍后注销,这在很多情况下会被忘记?
这就是 LRNotificationObserver 试图解决的问题。
使用 CocoaPods
将 LRNotificationObserver 添加到您的 Podfile 中
platform :ios, "6.0"
pod 'LRNotificationObserver'
运行以下命令
pod install
手动
克隆项目或将它作为子模块添加。将整个 LRNotificationObserver 文件夹拖拽到您的项目中。
要监听通知,您必须创建一个 LRNotificationObserver 实例。为此,只需使用以下方法。
+ (instancetype)observerForName:(NSString *)name
block:(LRNotificationObserverBlock)block;
当触发具有该名称的通知时,将执行该代码块。
LRNotificationObserverBlock 包含 NSNotification 实例。
typedef void(^LRNotificationObserverBlock)(NSNotification *note);
想象一下,您想要监听后台通知,而不是使用 NSNotificationCenter 并仅在dealloc中实现注销,您可以在您想要处理通知的对象(例如视图控制器)中简单地持有一个 LRNotificationObserver 属性,并在对象死亡时释放它。不再需要仅仅为了注销而重载 dealloc。这样更简单,如下所示。
@property (nonatomic, strong) LRNotificationObserver *backgroundObserver;
self.backgroundObserver = [LRNotificationObserver observerForName:UIApplicationDidEnterBackgroundNotification
block:^(NSNotification *note) {
// Do appropriate background task
}];
LRNotificationObserver 中最有趣的方法是 stopObserving,如果您要在dealloc之外的其他地方注销。
大多数时候,您只有在 dealloc 中注销。需要创建观察者属性以保持其活动状态可能会有些烦人。当然,实现 dealloc 来执行注销会更clean,但完全不这样做会更干净。有方法可以做到这一点,只需使用以下方法。
+ (void)observeName:(NSString *)name
owner:(id)owner
block:(LRNotificationObserverBlock)block;
您必须提供一个所有者,该所有者负责保留在幕后创建的观察者。不用担心,这个所有者不会被保留。观察者将在运行时附加到所有者,并在后者被析构时释放。
想象一下,您想监听内存警告通知。只需使用以下代码。
[LRNotificationObserver observeName:UIApplicationDidReceiveMemoryWarningNotification
owner:self
block:^(NSNotification *note) {
// Purge unnecessary cache
}];
就是这样,没有dealloc,没有新属性,只有这段代码。当然,还有其他更隐蔽的方法可以实现相同的功能。
有各种方式接收通知回调。您可以使用块或目标-动作模式,并指定您希望接收回调的队列(NSOperationQueue 和 dispatch queue)。您还可以指定您想要接收通知的对象。
想象一下,您希望接收到通知时在特定方法中更新 UI。以下代码可以实现这一功能。
[LRNotificationObserver observeName:@"someNotificationThatShouldUpdateTheUI"
object:anObject
owner:anOwner
dispatch_queue:dispatch_get_main_queue()
target:viewController
selector:@selector(methodToBeExecutedOnMainThread:)];
当使用目标-动作回调时,您可以决定是否接收通知对象(在选择器中指定冒号)。就像 Apple 所说的那样,与 NSNotificationCenter 的 addObserver:selector:name:object: 一样......
notificationSelector
Selector that specifies the message the receiver sends notificationObserver to notify it of the notification posting. The method specified by notificationSelector must have one and only one argument (an instance of NSNotification).
运行测试与执行 rakefile 一样简单。
rake
要运行简单示例,请记住首先安装 cocoa pods 依赖项。
rake test:cocoa_pods
LRNotificationObserver 需要 iOS 6.0 或 Mac OS X 10.8 以及 ARC。
您仍然可以在非 ARC 项目中使用 LRNotificationObserver。只需在每个源文件中设置 -fobjc-arc 编译器标志。
LRNotificationObserver 由 Luis Recuenco 创建:@luisrecuenco。
如果您想为项目做贡献,只需按照以下步骤操作
LRNotificationObserver可在MIT许可下使用。有关更多信息,请参阅“LICENSE文件”。