Block很简单,就像delegate的简化版
代理设计模式对于iOS开发的人来说肯定很熟悉了,代理delegate就是委托另一个对象来帮忙完成一件事情,为什么要委托别人来做呢,这其实是MVC设计模式中的模块分工问题,例如View对象它只负责显示界面,而不需要进行数据的管理,数据的管理和逻辑是Controller的责任,所以此时View就应该将这个功能委托给Controller去实现,当然你作为码农强行让View处理数据逻辑的任务,也不是不行,只是这就违背了MVC设计模式,项目小还好,随着功能的扩展,我们就会发现越写越难写;还有一种情况,就是这件事情做不到,只能委托给其他对象来做了,下面的例子中我会说明这种情况。
下面的代码我想实现一个简单的功能,场景描述如下:TableView上面有多个CustomTableViewCell,cell上面显示的是文字信息和一个详情Button,点击button以后push到一个新的页面。为什么说这个场景用到了代理delegate?因为button是在自定义的CustomTableViewCell上面,而cell没有能力实现push的功能,因为push到新页面的代码是这样的,
[self.navigationController pushViewController...];
所以这时候CustomTableViewCell就要委托它所在的Controller去做这件事情了。
按照我的编码习惯,我喜欢把委托的协议写在提出委托申请的类的头文件里面,现在的场景中是CustomTableViewCell提出了委托申请,下面是简单的代码,
@protocol CustomCellDelegate <NSObject>
- (void)pushToNewPage;
@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有如下几种使用情况,
1、作为一个本地变量(local variable)
returnType (^blockName)(parameterTypes) = ^returnType(parameters) {...};
2、作为@property
@property (nonatomic, copy) returnType (^blockName)(parameterTypes);
3、作为方法的参数(method parameter)
- (void)someMethodThatTakesABlock:(returnType (^)(parameterTypes))blockName;
4、作为方法参数的时候被调用
[someObject someMethodThatTakesABlock: ^returnType (parameters) {...}];
5、使用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,有兴趣的可以加进来讨论讨论、学习学习,也希望牛逼的大神到群里给我们菜鸟指点指点。
Block很简单,就像delegate的简化版的更多相关文章
- 关于Block的简单使用
Block在整个iOS开发中无所不见,很重要,很重要,文本在这里block的简单使用介绍.我们可以简单地定义.使用block. 1. Block和C的指针函数很像,但比C的函数灵活多了.废话了.... ...
- OC block的简单使用
http://blog.csdn.net/itpeng523/article/details/23965147 一.先用Xcode创建一个空工程 学习block之前先用弄懂c语言的函数指针 看代码: ...
- 手把手教你开发chrome扩展一:开发Chrome Extenstion其实很简单
手把手教你开发chrome扩展一:开发Chrome Extenstion其实很简单 手把手教你开发chrome扩展一:开发Chrome Extenstion其实很简单 手把手教你开发Chrome扩 ...
- 很简单的Java断点续传实现原理
原理解析 在开发当中,"断点续传"这种功能很实用和常见,听上去也是比较有"逼格"的感觉.所以通常我们都有兴趣去研究研究这种功能是如何实现的? 以Java来说,网 ...
- iOS - Block的简单使用
Block 的使用有两种: .独立Block .内联Block <一>独立Block 使用方式 一.定义一个Block Object,并调用. 1.定义 // 定义一个Bl ...
- Flutter:Slivers大家族,让滑动视图的组合变得很简单!
今天呢,我小拉面主要想给大家讲一讲Flutter中的Slivers大家族的使用场景和方法.开发过列表布局的同学们应该对Slivers系列的控件不陌生,或多或少都用过这个库中的控件,来解决复杂的滑动嵌 ...
- log4j入门(转) --- 很详细 也很简单容易懂
log4j入门(转) Log4j实在是很熟悉,几乎所有的Java项目都用它啊.但是我确一直没有搞明白.终于有一天我受不了了,定下心去看了一把文档,才两个小时,我终于搞明白了.一般情况下Log4j总是和 ...
- v86.01 鸿蒙内核源码分析 (静态分配篇) | 很简单的一位小朋友 | 百篇博客分析 OpenHarmony 源码
本篇关键词:池头.池体.节头.节块 内存管理相关篇为: v31.02 鸿蒙内核源码分析(内存规则) | 内存管理到底在管什么 v32.04 鸿蒙内核源码分析(物理内存) | 真实的可不一定精彩 v33 ...
- [.NET] 打造一个很简单的文档转换器 - 使用组件 Spire.Office
打造一个很简单的文档转换器 - 使用组件 Spire.Office [博主]反骨仔 [原文]http://www.cnblogs.com/liqingwen/p/6024827.html 序 之前,& ...
随机推荐
- JavaScript 闭包整合
初遇闭包感觉很困惑,上网查看了些许介绍,有很多没看懂,就想先对能懂的东西整整 首先觉得要了解闭包,要先对一.JavaScript的变量作用域和作用域链有基本了解 1.变量的作用域分为:全局变量和局部变 ...
- mysql笔记04 MySQL高级特性
MySQL高级特性 1. 分区表:分区表是一种粗粒度的.简易的索引策略,适用于大数据量的过滤场景.最适合的场景是,在没有合适的索引时,对几个分区进行全表扫描,或者是只有一个分区和索引是热点,而且这个分 ...
- XP+devOps开发模式与scrum敏捷开发对比,docker虚拟化
XP+devOps开发模式与scrum敏捷开发对比,docker虚拟化 我们现在用的就是典型的XP+devOps模式,已经放弃scrum了 现在还很多公司弄docker虚拟化docker非常复杂,当然 ...
- 如何杀掉D状态的进程?[zt]【转】
转自:http://blog.csdn.net/chinalinuxzend/article/details/4288791 [-] 如何杀掉D状态的进程zt 相关博文 原贴:http://www ...
- Java 基本数据类型 sizeof 功能【转】
转自:http://blog.csdn.net/sunboy_2050/article/details/7310008 版权声明:本文为博主原创文章,未经博主允许不得转载. Java基本数据类型int ...
- 用excel2010 制作复合图表
用excel2010制作双轴柱线复合图表就是要用excel2010做一个这样的图表:
- 9、Http回顾/Servlet
1 Http回顾 Http协议: 1)http协议: 对浏览器客户端和服务器端之间数据传输的格式规范. 2)http请求:浏览器->服务器端 格式: 请求行(请求方式(GET/POST) 请求资 ...
- socket的心跳包机制
网络中的接收和发送数据都是使用操作系统中的SOCKET进行实现.但是如果此套接字已经断开,那发送数据和接收数据的时候就一定会有问题.可是如何判断这个套接字是否还可以使用呢?这个就需要在系统中创建心跳机 ...
- 20145227 《Java程序设计》实验五实验报告
20145227 <Java程序设计>实验五实验报告 实验内容 1.掌握Socket程序的编写: 2.掌握密码技术的使用: 3.设计安全传输系统. 实验过程 1.先运行TCP代码,一人服务 ...
- java 面试每日一题
题目:一球从100米高度自由落下,每次落地后反跳回原高度的一半:再落下,求它在 第10次落地时,共经过多少米?第10次反弹多高? import java.util.Scanner; public cl ...