一个基本的 pub/sub 事件机制,可以为您处理订阅者生命周期!
iOS为单个对象通知其他对象提供了一些非常好的方法,让我们看看吧..
通知属性变化的一个相当好的方法,可以有多个订阅者,并在您订阅时提供一个初始值,这在 MVVM 设置中非常实用。但是也有一些缺点..首先,您只能通知属性值的更改,除此之外没有其他任何通知;其次(也是我认为的一个非常大的疏漏)是没有内置的方式来跟踪订阅者,如果您未能取消订阅,则会导致内存泄漏,但如果您尝试在实际上并未订阅时取消订阅,则会引发异常..但它并不全是坏事..Facebook有一个非常好的KVOController,它可以为您处理大部分这些问题!
还值得一提的是,KVO甚至还没有被原生整合到 Swift 中!(您仍然需要将 Swift 类伪装成 Objective-C 类..嗯..)
相对于 KVO,NSNotificationCenter 在 KVO 的优点基础上做了一些改进,但无法获取初始值。尽管如此,它通过内置的方式跟踪您是否已订阅以及 NSNotifications 可以发送一些额外的数据供您消费进行了改进。经过快速搜索,我发现了一个这个存储库,该存储库似乎修改了 KVOController 以处理 NSNotificationCenter 订阅者生命周期。
另一种广泛使用的对象发生事件通知对象的方法。您可以根据需要包含任何参数,并且通常可以通过将委托声明为 弱
来很好地处理生命周期。然而,这是一个单一订阅者机制,当然,您可以将其更改为委托数组以包含更多订阅者,但这会失去使用弱引用提供的生命周期管理。
最终我们得到了块,这是他们提供的另一种单一订阅者模式,其优缺点与委托模式相同,区别在于订阅者可以直接在其订阅代码所在的地方处理事件。这通常看起来是个好主意,对像UIAlertView这样的东西来说也很有道理,但如果你在订阅者中将大量事件处理块混合在一起,可能会使你的代码变得不那么易于阅读。
所以我们有处理事件的各种方法...为什么还需要另一个呢?这是个好问题...你可能不需要。使用 IKEvent
可能不适合你的用例,但让我们看看如何设置它。
@interface EventPublisher: NSObject
@property (readonly) IKEvent *myEvent;
@end
@implementation EventPublisher
-(instancetype)init {
if (!(self = [super init])) { return nil; }
_myEvent = [IKEvent new];
return self;
}
-(void)methodThatTiggersEvent {
/* some misc code.. */
notify(self.myEvent, someParameter);
}
@end
非常简单,要订阅,你只需要
-(void)methodThatSubscribes:(EventPublisher *)publisher {
[publisher.myEvent add:self selector:@selector(myEventHappened:)];
}
-(void)myEventHappened:(id)parameter { ... }
就这样...其余的都由它接管,如果包含 methodThatSubscribes:
的对象被销毁,EventPublisher
会将其从订阅者列表中移除,不会发生任何坏事!
你可以使用目标/选择器或块来响应每次发生的事件,对于一个事件
@property (readonly) IKEvent *newNumberValue; //parameters are 'NSNumber *oldValue' and 'NSNumber *newValue'
要使用目标/选择器进行订阅,请使用 add:selector:
-(void)methodThatSubscribes:(IKEvent *)event {
[event add:self selector:@selector(numberChangedFrom:to:)];
}
-(void)numberChangedFrom:(NSNumber *)oldValue to:(NSNumber *)newValue { ... }
或使用块使用 add:block:
-(void)methodThatSubscribes:(IKEvent *)event {
[event add:self block:^(NSNumber *oldValue, NSNumber *newValue) {
/* ... */
}];
}
你还可以只为单一事件发生一次监听。使用 once:selector:
-(void)methodThatSubscribes:(IKEvent *)event {
[event once:self selector:@selector(numberChangedFrom:to:)];
}
-(void)numberChangedFrom:(NSNumber *)oldValue to:(NSNumber *)newValue { ... }
或使用块使用 once:block:
-(void)methodThatSubscribes:(IKEvent *)event {
[event once:self block:^(NSNumber *oldValue, NSNumber *newValue) {
/* ... */
}];
}
订阅者收到事件一次后,将从订阅者列表中移除。
通知就像使用
notify(event, param1, param2, param3, ...)
目前支持 0 到 5 个参数,但如果你需要更多,可以提交一个 PR!添加更多参数轻而易举 :)
有时候你可能有一个中间对象需要将其事件转发给自己的订阅者,当你只想用相同的参数重新触发它时,必须订阅一个事件真是太讨厌了!
@interface IntermediaryObject: NSObject
@property (readonly) IKEvent *myEvent;
@end
@implementation IntermediaryObject
-(void)forwardEvent:(IKEvent *)event {
[event addForwarding:self.myEvent];
}
@end
现在每当 event
触发时,myEvent
会使用相同的参数(如果有任何)触发
当你完成一个事件并且不再想要被通知时,只需调用
-(void)unsubscribeFrom:(IKEvent *)evvent {
//stop receiving notifications about this event
[event remove:self];
/* or */
//stop forwarding notifications of this event
[event removeForwarding:self.myEvent];
/* or */
//completely removes all subscribers and forwarding from an event
[event removeAllTargetsAndForwarding];
}
或者通过将 IKEvents
子目录中的源文件手动添加到你的项目中
欢迎拉取请求!
如果你在项目中使用它,我很乐意听听!..
向惊人的 PromiseKit 致敬,我借鉴了其 NSMethodSignatureForBlock
实现
我通常在 iOS Developers 上闲逛。你应该去看看他们!