博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
所闻所获2:使用块回调来实现代理的功能
阅读量:4348 次
发布时间:2019-06-07

本文共 3454 字,大约阅读时间需要 11 分钟。

  首先回顾一下代理模式,它的基本说明如下图:

 

  控制器先成为子控件的代理(delegate)并实现相应的代理方法,那么子控件在运作的过程中,遇到某些需要控制器进行配合的场景时,就可以通过delegate属性调用对应场景的代理方法,实现让控制器进行对应操作的效果。

 

  块回调的基本模式如下图:

 

  块回调方法的模型是这样的:在一个方法B内嵌套另一个方法C,当其他地方的方法A使用B这个方法的时候,B方法能够通过C来将一些信息传递回给A方法,A自己就可以拿到传回来的这些信息进行操作(C的调用在B内,具体实现在A内)。

 

  下面以一个自定义的segmentControl为例来演示如何使用块回调来实现代理的效果,要求点击这个segmentControl上的按钮后,页面会有相应反应。它的效果如下图:

  具体代码可在以下链接下载:

  首先看看使用代理模式的实现方法:

(1)、首先定义segmentControl,这个自定义控件是根据初始化方法传进来的frame和按钮标题数组把整个segmentControl等分为对应个数的UIButton,这个最主要的初始化入口方法如下:

- (instancetype)initWithTitles:(NSArray *)titles frame:(CGRect)frame delegate:(id
) theDelegate { if (self = [super initWithFrame:frame]) { ...//把传进来的参数赋给自身属性 self.delegate = theDelegate;//把传进来的控制器设为代理 [self configView];//初始化segmentControl的各部分布局 return self; } return nil;}

(2)、然后在segmentControl里的UIButton的点击监听方法如下:

-(void)buttonClick:(UIButton *)button{    self.selectedIndex = button.tag; //记录下点击的是哪个按钮    [self refreshButton]; //根据记录的内容刷新按钮的显示    //然后使用delegate调用代理方法,让控制器执行对应代码    if ([self.delegate respondsToSelector:@selector(segmentControl:didSelectedIndex:)]) {        [self.delegate segmentControl:self didSelectedIndex:self.selectedIndex];    }}

(3)、在控制器中,viewDidLoad方法首先调用了usingDelegate方法来初始化segmentControl,usingDelegate方法的代码如下:

- (void)usingDelegate {    NSArray *items = ...    CGRect segmentControlFrame = ...    SYSegmentControl *segmentControl = [[SYSegmentControl alloc]initWithTitles:items frame:segmentControlFrame delegate:self];    [self.view addSubview:segmentControl];    //refreshView方法会根据self.selectedIndex的内容决定显示什么内容    [self refreshView];}

同时这种模式还需要代理方法的配合,控制器需要实现对应的代理方法,如下:

- (void)segmentControl:(SYSegmentControl *)segmentControl didSelectedIndex:(NSInteger)index {    self.selectedIndex = index;    [self refreshView];}

在整个过程中,当segmentControl中的某个按钮被点中之后,按钮的点击监听方法会被调用,在这个方法中使用delegate(也就是控制器)去调用对应的代理方法,在控制器实现的代理方法中,根据segmentControl传过来的参数去刷新页面,显示对应内容。

 

  然后看看使用块回调模式的实现方法:

(1)、块回调模式中,segmentControl的初始化入口方法和代理模式的有所区别,代码如下:

- (instancetype)initWithTitles:(NSArray *)titles frame:(CGRect)frame callback:(callbackBlock)block{    if (self = [super initWithFrame:frame]) {        ...//把传进来的参数赋给自身属性        self.block = block; //把传进来的块赋给自身属性        [self configView];        return self;    }    return nil;}

(2)、segmentControl的按钮点击方法修改如下:

//两种模式共用一个点击触发方法,在方法内判断模式类型-(void)buttonClick:(UIButton *)button{    ...    if (...) {        //省略代理模式的代码        ...    }else if (self.block) {        //在此处进行块回调        self.block(self.selectedIndex);    }}

(3)、在控制器中,viewDidLoad方法首先调用了usingBlockCallback方法来初始化segmentControl,代码如下:

- (void)usingBlockCallback {    NSArray *items = ...    CGRect segmentControlFrame = ...    __weak ViewController *weakself = self;    SYSegmentControl *segmentControl = [[SYSegmentControl alloc]initWithTitles:items frame:segmentControlFrame callback:^(NSInteger index) {        //块回调会回调到下面这两句代码        weakself.selectedIndex = index;        [weakself refreshView];    }];    [self.view addSubview:segmentControl];       [self refreshView];}

在这个过程中,控制器在初始化segmentControl的时候就将需要回调的代码也定义好了,segmentControl在需要控制器配合的时候,可以直接调用块实现回调控制器里的块代码的效果,控制器只需在块代码里定义好对应操作即可。

 

  对比两种方法可以发现,使用块回调回比使用代理更加轻便,因为不需要去声明协议以及代理方法,也不用去实现代理方法,只需把要回调的内容定义在块参数里即可。

  但是在使用场景比较复杂的情况下,块代码回调这种方式就不如代理模式了。比如说要实现在segmentControl刚开始点击、刚放开点击或者在某个特定按钮状态下点击另一个按钮等这些场景中让控制器做相应反应,那么块回调方式实现起来就不如代理模式了,需要定义多个块参数以对应多种回调情况,会让segmentControl的初始化方法显得臃肿。这时候使用代理模式可以比较清晰区分各个场景的逻辑。

 

转载于:https://www.cnblogs.com/shayneyeorg/p/4657833.html

你可能感兴趣的文章
ES6/ES2015核心内容 import export
查看>>
pid参数调节的几句话
查看>>
Day4-文件,json字典文件互转,函数
查看>>
.Net core 使用Jenkins + Docker + Azure Devops 持续部署(CI/CD)
查看>>
iOS_SN_UITableView的优化
查看>>
vector引用参数
查看>>
[转载]typedef 的用法
查看>>
NTC温度采集之数据拟合——freemat软件实现
查看>>
maven私服nexus3.9安装配置
查看>>
U盘出现大量乱码文件,并且不能彻底删除
查看>>
UEditor添加一个普通按钮及其他使用注意事项
查看>>
C语言的第一次实验报告
查看>>
spring JDBC 批量插入数据
查看>>
状态压缩题目小结
查看>>
Android WebView 开发具体解释(三)
查看>>
2016-2017-2 20155325实验二《Java面向对象程序设计》实验报告
查看>>
POJ.3145.Common Substrings(后缀数组 倍增 单调栈)
查看>>
BZOJ.1935.[SHOI2007]Tree园丁的烦恼(CDQ分治 三维偏序)
查看>>
c++可变参数(示例)
查看>>
4923: [Lydsy1706月赛]K小值查询 平衡树 非旋转Treap
查看>>