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 序 之前,& ...
随机推荐
- zw版【转发·台湾nvp系列Delphi例程】HALCON HighpassImage
zw版[转发·台湾nvp系列Delphi例程]HALCON HighpassImage unit Unit1;interfaceuses Windows, Messages, SysUtils, Va ...
- TortoiseGit文件夹和文件图标不显示解决方法
试了两种方法, 1.修改Max Cached Icons http://www.open-open.com/lib/view/open1414396787325.html 2.修改图标排序 http: ...
- 文字处理控件TX Text Control X10独家揭秘(一):数据源自动处理
TX Text Control即将发布的X10版本,将升级重点还是放到了其比较优势的流式布局报表设计和生成上.慧都获得了来自其开发商Text Control GmbH公司的一手资料,迫不及待的为大家带 ...
- nodejs和mongodb实践
首先,当然是都安装了nodejs 和mongodb了.这必须是前提条件. 现在我们要用nodejs连接mongodb数据库了.我这里只是一个非常非常简单是实践,初学嘛.更深入的学习之后,我会仔细写笔记 ...
- 160928、JQuery解析XML数据的demo
用JavaScript解析XML数据是常见的编程任务,JavaScript能做的,JQuery当然也能做.下面我们来总结几个使用JQuery解析XML的例子. 方案1 当后台返回的数据类型是xml对象 ...
- 160919、使用AOP与注解记录Java日志
有些时候,我想要把每个运行过的方法接收到的参数.返回值和执行时间等信息记录(通过slf4j 和 log4j)下来.在AspectJ.jcabi-aspects和Java注解的帮助下我实现了这个想法. ...
- 编程之美_1.1 让CPU占用率曲线听你指挥
听到有人说让要写一个程序,让用户来决定Windows任务管理器的CPU占用率. 觉得很好奇.但第一个想法就是写个死循环.哈哈.不知道具体的占用率是多少,但至少能保证在程序运行时,CPU的占用率终会稳定 ...
- Linux下创建与解压tar, tar.gz和tar.bz2文件及压缩率对比 | 沉思小屋
刚 在qq群里面一位仁兄问到文件压缩的命令,平时工作中大多用解压缩命令,要是遇到压缩就现查(这不是一个好习惯),于是整理下Linux下创建与解压 zip.tar.tar.gz和tar.bz2文件及他们 ...
- Mootools插件-闪烁的标题
转自:http://www.cnblogs.com/see7di/archive/2012/10/09/2716024.html 回想起来,我已经好久没有写点啥了,尤其是关于Mootools方面的东西 ...
- Python基础第一篇
一.第一句python代码 1.python执行过程:1.加载内存-词法分析-语法分析-编译-执行 2.创建hello.py文件,输入内容 #!/usr/bin/env python print &q ...