代理设计模式对于iOS开发的人来讲确定很熟悉了,代理delegate就是委托另外一个对象来帮忙完成一件事情,为何要委托别人来作呢,这实际上是MVC设计模式中的模块分工问题,例如View对象它只负责显示界面,而不须要进行数据的管理,数据的管理和逻辑是Controller的责任,因此此时View就应该将这个功能委托给Controller去实现,固然你做为码农强行让View处理数据逻辑的任务,也不是不行,只是这就违背了MVC设计模式,项目小还好,随着功能的扩展,咱们就会发现越写越难写;还有一种状况,就是这件事情作不到,只能委托给其余对象来作了,下面的例子中我会说明这种状况。python
下面的代码我想实现一个简单的功能,场景描述以下:TableView上面有多个CustomTableViewCell,cell上面显示的是文字信息和一个详情Button,点击button之后push到一个新的页面。为何说这个场景用到了代理delegate?由于button是在自定义的CustomTableViewCell上面,而cell没有能力实现push的功能,由于push到新页面的代码是这样的,ios
[self.navigationController pushViewController...];git
因此这时候CustomTableViewCell就要委托它所在的Controller去作这件事情了。github
按照个人编码习惯,我喜欢把委托的协议写在提出委托申请的类的头文件里面,如今的场景中是CustomTableViewCell提出了委托申请,下面是简单的代码,设计模式
@protocol CustomCellDelegate <NSObject>服务器
- (void)pushToNewPage;ide
@end 函数
@interface CustomTableViewCell : UITableViewCell学习
@property(nonatomic, assign) id<CustomCellDelegate> delegate;编码
@property (nonatomic, strong) UILabel *text1Label;
@property(nonatomic,strong) UIButton *detailBtn;
上面的代码在CustomTableViewCell.h中定义了一个协议CustomCellDelegate,它有一个须要实现的pushToNewPage方法,而后还要写一个属性修饰符为assign、名为delegate的property,之因此使用assign是由于这涉及到内存管理的东西,之后的博客中我会专门说明缘由。
接下来在CustomTableViewCell.m中编写Button点击代码,
[self.detailBtn addTarget:self action:@selector(btnClicked:) forControlEvents:UIControlEventTouchUpInside];
对应的btnClicked方法以下,
- (void)btnClicked:(UIButton *)btn
{
if (self.delegate && [self.delegaterespondsToSelector:@selector(pushToNewPage)]) {
[self.delegate pushToNewPage];
}
}
上面代码中的判断条件最好是写上,由于这是判断self.delegate是否为空,以及实现CustomCellDelegate协议的Controller是否也实现了其中的pushToNewPage方法。
接下来就是受到委托申请的类,这里是对应CustomTableViewCell所在的ViewController,它首先要实现CustomCellDelegate协议,而后要实现其中的pushToNewPage方法,还有一点不能忘记的就是要设置CustomTableViewCell对象cell的delegate等于self,不少状况下可能忘了写cell.delegate = self;致使遇到问题不知云里雾里。下面的关键代码都是在ViewController.m中,
首先是服从CumtomCellDelegate协议,这个你们确定都知道,就像不少系统的协议,例如UIAlertViewDelegate、UITextFieldDelegate、UITableViewDelegate、UITableViewDatasource同样。
@interface ViewController ()<CustomCellDelegate>
@property (nonatomic, strong) NSArray *textArray;
而后是实现CustomCellDelegate协议中的pushToNewPage方法,
- (void)pushToNewPage
{
DetailViewController*detailVC = [[DetailViewController alloc] init];
[self.navigationController pushViewController:detailVC animated:YES];
}
还有一个步骤最容易被忘记,就是设置CumtomTableViewCell对象cell的delegate,以下代码,
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *simpleIdentify = @"CustomCellIdentify";
CustomTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:simpleIdentify];
if (cell == nil) {
cell = [[CustomTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:simpleIdentify];
}
//下面代码很关键
cell.delegate = self;
cell.text1Label.text = [self.textArray objectAtIndex:indexPath.row];
return cell;
}
经过cell.delegate = self;确保了CustomTableViewCell.m的判断语句if(self.delegate && ...){}中得self.delegate不为空,此时的self.delegate其实就是ViewController,cell对象委托了ViewController实现pushToNewPage方法。这个简单的场景描述了使用代理的一种状况,就是CustomTableViewCell没有能力实现pushViewController的功能,因此委托ViewController来实现。
代码在github能够下载。
有什么错误,还请你们指正。
----------------------------------------------下面是block的内容----------------------------------------------------
Block是一个C语言的特性,就像群里有人说的,它就是C语言的函数指针,在使用中最多的就是进行函数回调或者事件传递,好比发送数据到服务器,等待服务器反馈是成功仍是失败,此时block就派上用场了,这个功能的实现也可用使用代理,这么说的话,感受block是否是有点像代理了呢?
我以前接触block,都是使用它做为函数参数,当时感受不是很理解。如今在项目中,不少时候block做为property,这样更加简单直接,想一想,其实property不就是定义的合成存储的变量嘛,而block做为函数参数也是定义的变量,因此做为函数参数或者做为property本质没有区别。
看一看别人总结的block的语法吧,http://fuckingblocksyntax.com,这个连接亮了,fucking block syntax,操蛋的block语法啊。block有以下几种使用状况,
一、做为一个本地变量(local variable)
returnType (^blockName)(parameterTypes) = ^returnType(parameters) {...};
二、做为@property
@property (nonatomic, copy) returnType (^blockName)(parameterTypes);
三、做为方法的参数(method parameter)
- (void)someMethodThatTakesABlock:(returnType (^)(parameterTypes))blockName;
四、做为方法参数的时候被调用
[someObject someMethodThatTakesABlock: ^returnType (parameters) {...}];
五、使用typedef来定义block,能够事半功倍
typedef returnType (^TypeName)(parameterTypes);
TypeName blockName = ^returnType(parameters) {...};
上面我也只是复制粘贴了一下,接下来仍是实现点击CustomTableViewCell上面的Button实现页面跳转的功能,我以前不止一次的类比block就像delegate,这边我也是思惟惯性,下面的内容我就当block为代理,一些用词描述仍是跟delegate差很少。首先,在提出委托申请的CustomTableViewCell中定义block的property,
@interface CustomTableViewCell : UITableViewCell
@property (nonatomic, strong) UILabel *text1Label;
@property (nonatomic, strong) UIButton *detailBtn;
//下面的定义,请看官们对比一下
/*delegate的定义 我没有删除,由于你们能够类比了看下*/
@property (nonatomic, assign) id<CustomCellDelegate> delegate;
/*这里定义了ButtonBlock*/
@property (nonatomic, copy) void (^ButtonBlock)();
@end
这里用copy属性来修饰ButtonBlock property,这个缘由,我会在之后的博客中做专门的解释。
接下来在CustomTableViewCell中给它上面的detailBtn绑定点击方法,
[self.detailBtn addTarget:self action:@selector(btnClicked:) forControlEvents:UIControlEventTouchUpInside];
而后是btnClicked方法的细节,我把delegate的内容也没有删除,就是给各位比较一下block和delegate的功能和语法的类似性,
- (void)btnClicked:(UIButton *)btn
{
//这是以前的delegate
if (self.delegate && [self.delegate respondsToSelector:@selector(pushToNewPage)]) {
[self.delegate pushToNewPage];
}
//这是如今咱们要说的block
if (ButtonBlock) {
ButtonBlock();
}
}
下面是一个关键性的地方,在ViewController2中设置其CustomTableViewCell的cell对象的ButtonBlock,也就是给它赋值,此处我仍是保留了cell.delegate = self;代码,
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *blockIdentify = @"BlockIdentify";
CustomTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:blockIdentify];
if (cell == nil) {
cell = [[CustomTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:blockIdentify];
}
cell.text1Label.text = [self.textArray objectAtIndex:indexPath.row];
//delegate的不可缺乏的代码,这里放在这儿只是为了给各位类比一下
cell.delegate = self;
//ButtonBlock不可缺乏的代码
cell.ButtonBlock = ^{
[self pushToNewPage2];
};
return cell;
}
之因此cell.ButtonBlock = ^{};赋值,是由于咱们咱们是这样定义ButtonBlock的,void (^ButtonBLock)(),表示无返回值无参数。
而后编写pushToNewPage2方法,
- (void)pushToNewPage2
{
DetailViewController *detailVC = [[DetailViewController alloc] init];
[self.navigationController pushViewController:detailVC animated:YES];
}
大家看这个方法是否是与CustomCellDelegate协议中的pushToNewPage方法相似。而后在回过头来类比同样,是否是block就是精简版的delegate,由于delegate设计模式要写协议CustomCellDelegate,还有容易遗漏cell.delegate = self;可是block使用的时候就简单多了。
最新的代码我已经更新到github,很是简单,有疑问或者有质疑的朋友能够下载看看。
另:本人也是ios开发菜鸟,对于不少的细节了解不够深刻,上面的代码使用arc编码,若是我写的有什么问题或者有什么缺陷的话,还请大神给我指正。
很但愿有各位开发者相互交流,提升技术,个人邮箱:zheniyerenrou@163.com。还有一个qq交流群188647173,有兴趣的能够加进来讨论讨论、学习学习,也但愿牛逼的大神到群里给咱们菜鸟指点指点。