通知/代理/block实需处理
2018-06-18 本文已影响410人
RocketsChen
由于最近手上的项目页面间的互动感比较强,在处理问题的时候又思考一下老生常谈的三种回调处理方式。如下以假设实需为例:
Block:
-
1.声明Block
-
2.调用/处理回调
warning: 防止内存循环
Delegate:
-
1.声明代理属性和协议方法
-
2.设置和调用代理中
-
3.在绑定页面实现协议方法
warning: 遵守协议,实现协议方法注意方法属性@required和@optional
Notification:
-
1.注册通知
-
2.发通知
-
3.移除通知
warning: 移除通知
三者比较:从消息的角度:Notification:“一对多”、“多对一”、Block和Delegate都是“一对一”。从结构上上:Block块状代码较为简洁更轻巧。从性能的角度:Block和Delegate比Notification性能高。
实需举例如:A控制器跳转到B —> B跳转到C —> C跳转到D D做一些事后返回B/A (点击)进入B界面 B根据D的改变产生回调。
如果只是简单的在实现角度上刚入门应该就可以解决了,一个通知搞定收工。但是这仅仅是D对B的一个需求。那么C对A、E对C等等;都以通知的方式去处理:那么频繁的发通知会导致很多不必要的麻烦如
- 接受消息对象多了,难以控制
- dealloc遗漏处理remove掉
- 执行效率低下(相比较Delegate/Block)
以下用三种方式处理上面假设的需求:
✨代理:
- 在D.h设置代理属性和协议方法
@property (nonatomic, weak) id<DCBackDelegate> updateDelegate;//代理属性
@protocol DCBackDelegate <NSObject>
@optional
- (void)updateBackWithInfor:(NSString *)message; //协议方法
@end
- 在D.m遵守代理协议和调用协议方法并在B.m只是调用代理方法处理回调。
一般我们先需要遵守代理协议。伪代码就是:委托对象.delegate = self。这里我们需要搞清楚谁是委托对象,谁是Self ? 从最终实在B页面调用协议方法的角度上来说也就是B声明的对象就是伪代码中的self。那委托对象自然而然就是D声明的对象了。代码如下:
//1:在D页面取出B对象
NSString *noteStr = @"我回来了";
for (DCSecondViewController *secondVc in self.navigationController.viewControllers) {
if ([secondVc isKindOfClass:[DCSecondViewController class]]) {
[self.navigationController popToViewController:secondVc animated:YES];
//2:遵守协议
self.updateDelegate = secondVc;
//3:传值协议方法
if (self.updateDelegate && [self.updateDelegate respondsToSelector:@selector(updateBackWithInfor:)]) {
[self.updateDelegate updateBackWithInfor:noteStr];
}
}
}
- 在B.m就以直接调用了。
@interface DCSecondViewController : UIViewController <DCBackDelegate>
#pragma mark - <DCBackDelegate> 代理
- (void)updateBackWithInfor:(NSString *)message
{
[self alterSheetWithNote:message];
}
✨Block:
我们在B页面声明Block回调,在D页面调用,类似于用Block的方式在B.h页面声明一个方法在D调用。
//1:B.h声明
/** 更新B回调Block */
@property (nonatomic, copy) void(^updateBlock)(NSString *note);
//[图片上传中...(GIF.gif-bfd7ec-1529319531933-0)]
2:在D页面取出B对象
NSString *noteStr = @"我回来了";
for (DCSecondViewController *secondVc in self.navigationController.viewControllers) {
if ([secondVc isKindOfClass:[DCSecondViewController class]]) {
[self.navigationController popToViewController:secondVc animated:YES];
//3.Block
!secondVc.updateBlock ? : secondVc.updateBlock(noteStr);
break;
}
}
#pragma mark - Block
- (void)setUpBlockDo
{
__weak typeof(self)weakSelf = self;
self.updateBlock = ^(NSString *note) { //Block
[weakSelf alterSheetWithNote:note];
};
}
✨通知:
//1.发通知
dispatch_sync(dispatch_get_global_queue(0, 0), ^{
[[NSNotificationCenter defaultCenter]postNotificationName:@"UPDATENOTE" object:nil userInfo:@{@"note" : noteStr}];
});
//2:接受通知:
#pragma mark - 通知回调
- (void)setUpAcceptNote
{
__weak typeof(self)weakSelf = self;
[[NSNotificationCenter defaultCenter] addObserverForName:@"UPDATENOTE" object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification * _Nonnull note) {
[weakSelf alterSheetWithNote:note.userInfo[@"note"]];
}];
}
//3:移除
- (void)dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
