描述:git倉庫
iOS delegate秧秉、block屬于一對一的模式象迎。
有時(shí)候需要實(shí)現(xiàn)一對多的需求,通知可以實(shí)現(xiàn)呛踊。但有時(shí)候業(yè)務(wù)關(guān)聯(lián)是很緊密的砾淌,通知的可讀性不是很好。
項(xiàng)目中目前使用的是GCDMulticastDelegate,發(fā)現(xiàn)其有幾個(gè)缺點(diǎn):
- GCDMulticastDelegate中都是在消息轉(zhuǎn)發(fā)中進(jìn)行消息調(diào)用谭网,消息轉(zhuǎn)發(fā)在iOS中代價(jià)比較高汪厨。
- 其消息調(diào)用都是異步提交到隊(duì)列,導(dǎo)致堆棧信息無法跟蹤愉择。
- 庫也比較老了劫乱,偶現(xiàn)閃退。體驗(yàn)不是很好锥涕。
- 使用起來不太方便衷戈,需要先定義multiDelegate,添加代理,不用需要移除站楚,使用時(shí)還需要判斷方法是否存在脱惰。
@property(nonatomic, strong) GCDMulticastDelegate <BLEnterpriseManagerDelegate> *multiDelegate;
- (instancetype)init {
if (self = [super init]) {
self.multiDelegate = (GCDMulticastDelegate <BLEnterpriseManagerDelegate> *) [[GCDMulticastDelegate alloc] init];
}
return self;
}
- (void)addDelegate:(id <BLEnterpriseManagerDelegate>)delegate delegateQueue:(dispatch_queue_t)queue {
[_multiDelegate addDelegate:delegate delegateQueue:queue];
}
- (void)removeDelegate:(id <BLEnterpriseManagerDelegate>)delegate {
[_multiDelegate removeDelegate:delegate];
}
if ([self.multiDelegate hasDelegateThatRespondsToSelector:@selector(enterpriseManager:didClearAllOrgs:)]) {
[self.multiDelegate enterpriseManager:self didClearAllOrgs:YES];
}
思考
一對多就是觀察者模式的使用,完全可以自己實(shí)現(xiàn)搏嗡。
- 觀察者使用封裝在了NSObject擴(kuò)展中窿春,任何對象都可以添加觀察者對象。不再需要在被觀察者中聲明什么采盒。
- 消息調(diào)用使用了NSInvocation旧乞,不走消息轉(zhuǎn)發(fā)。
- 如果不設(shè)置隊(duì)列磅氨,默認(rèn)都回到主線程尺栖;也可指定隊(duì)列。
- 方法不存在烦租,不需要外部判斷延赌。內(nèi)部打印錯誤日志,注意觀察叉橱。
方案一
使用
- 導(dǎo)入頭文件
#import "NSObject+BLObserver.h" - 添加觀察者
[_customView wp_addObserver:self];
_observer1 = [WPViewObserver new];
_observer1.title = @"observer1 ";
[_customView wp_addObserver:_observer1];
_observer2 = [WPViewObserver new];
_observer2.title = @"observer2 ";
[_customView wp_addObserver:_observer2 delegateQueue:dispatch_queue_create("observer2", DISPATCH_QUEUE_SERIAL)];//指定隊(duì)列
- 被觀察者通知觀察者:帶參數(shù)調(diào)用
[self wp_notifyObserverWithAction:@selector(update), nil];
[self wp_notifyObserverWithAction:@selector(update:), 1,nil];
[self wp_notifyObserverWithAction:@selector(update:count2:), 1,2,nil];
- 觀察者監(jiān)聽
- (void)update:(NSInteger)count{
NSLog(@"detail update %ld",count);
}
- (void)update:(NSInteger)count count2:(NSInteger)count2{
NSLog(@"detail update %ld,%ld",count,count2);
}
- 退出頁面后內(nèi)存自動釋放
2021-02-06 23:18:16.655618+0800 WPObserver_Example[58471:640255] WPDetailViewController dealloc
2021-02-06 23:18:16.656013+0800 WPObserver_Example[58471:640255] WPViewObserver dealloc observer2
2021-02-06 23:18:16.656214+0800 WPObserver_Example[58471:640255] WPViewObserver dealloc observer1
2021-02-06 23:18:16.656621+0800 WPObserver_Example[58471:640255] WPView dealloc
小結(jié)
- 多數(shù)監(jiān)聽的或移除的時(shí)候都是在主線程挫以,如果覺得線程不安全,也可以加個(gè)信號量窃祝。
- 觀察者模式使用簡單掐松,要考慮到通用性,多參問題。
- 多參要考慮到int,double等基本類型大磺。
- weak不持有觀察者抡句,不需要釋放。只管監(jiān)聽杠愧,和通知觀察者待榔。如果有特殊情況,不需要監(jiān)聽了流济,可以調(diào)用[wp_removeObserver]究抓,移除監(jiān)聽;單例的監(jiān)聽者,需要手動移除袭灯。
方案二
以上方案可以實(shí)現(xiàn)通知刺下,調(diào)用wp_notifyObserverWithAction:,不支持泛型稽荧。
方案二去掉多參橘茉,加上線程安全,支持泛型姨丈。
使用
- 添加觀察者
- (void)addObserver2{
[_customView.proxyObserver addObserver:self];
[_customView.proxyObserver addObserver:_observer1];
[_customView.proxyObserver addObserver:_observer2 delegateQueue:dispatch_queue_create("observer2", DISPATCH_QUEUE_SERIAL)];//指定隊(duì)列
}
- 通知觀察者畅卓,支持泛型
[self.proxyObserver notifyObserver:^(id<WPViewObserver> _Nonnull target) {
[target update];
} selector:@selector(update)];
[self.proxyObserver notifyObserver:^(id<WPViewObserver> _Nonnull target) {
[target update:1];
} selector:@selector(update:)];
[self.proxyObserver notifyObserver:^(id<WPViewObserver> _Nonnull target) {
[target update:1 count2:2];
} selector:@selector(update:count2:)];
[self.proxyObserver notifyObserver:^(id<WPViewObserver> _Nonnull target) {
[target updateTitle:@"標(biāo)題" count:4];
} selector:@selector(updateTitle:count:)];