标签:delegate protocol block blocks ios
这是我原先写的OC中关于协议和代理的文章,建议大家阅读此篇文章的时候先阅读此文章,便于大家理解: IOS Protocol与Delegate详解(一) IOS Protocol与Delegate详解(二)
官方中对于Block的用途为:
You can use blocks to compose function expressions that can be passed to API, optionally stored, and usedby multiple threads. Blocks are particularly useful as a callback because the block carries both the code to beexecuted on callback and the data needed during that execution.
你可以使用Blocks组成方法表达式组成API接口,可选择的存储,或者运用其在不同的线程中,Blocks在回调中非常的重要因为Blocks携带了需要回调的代码和执行时的参数
从上面可以看出,
Blocks最最重要的地方就是可以用来回调,准确的是,是用来方便的回调
如果你看过我以前写的"Protocol与Delegate详解"的话,就会知道,Protocol(协议)可以看成是一个方法的集合,而block可以看成只有一个方法的确定名称的Protocol(协议),
也就是说,block可以说是一个不标准的协议,,类似于我们的口头协议
但是,就是这么一个不标准的协议,却很大的方便了我们程序的开发,试想,如果我去路边的小摊买一个冰棍,难道我和摊主还要签订一个买卖协议?不会,至少我没有见到过
如果真要通过协议的方法来实现上述交易过程的话其实也可以,即先定义一个买卖协议,其中有一个方法,传入值为金钱,返回值为商品对象,然后摊主实现此协议,我就可以调用摊主的这个协议中的方法,最后顺利吃上我的冰棍
你也许会想,这也太麻烦了,简直就是反人类,所以,我们可以让摊主实现一个传入值为金钱,返回值为商品对象的block对象。然后我去调用这个对象即可。
也就是说,我们定标准的时候不用在费尽的写一个协议,在让类实现这个协议,以后只需写一个blocks方法对象,然后直接调用即可
说了这么多,可能你对blocks还不太理解,没事,我们先从基础讲起
block的基础应用:
①.定义并使用blocks :
You use the ^ operator to declare a block variable and to indicate the beginning of a block literal. The body of the block itself is contained within {}
你可以使用^操作符来定义一个block变量,^操作符出现在block的开头。block的body在{}里面。
示例:
int multiplier = 7;
int (^myBlock)(int) = ^(int num) {
return num * multiplier;
};
//直接使用:
printf("%d", myBlock(3));
// prints "21"
注意,这种使用方法是直接将myBlock当做一个指向普通方法的指针来使用的,你可能有疑惑,我只向myBlock传了一个参数3(即是blocks中的num参数)啊,multiplier在哪呢,multiplier在myBlock的上面。下面是API文档中的解释:
Notice that the block is able to make use of variables from the same scope in which it was defined.
所以myBlock可以直接使用multiplier变量
下面是上述block的示例图:
②.直接使用blocks来进行回调 :
上面定义并使用blocks的方法就不在多说了,在自己类中定义并使用blocks)不是经常被使用,我们使用blocks一般是用作回调
使用我之前写的Delegate中的一个例子: IOS Protocol与Delegate详解(二) 我们把里面的"小李买茶"的例子使用blocks来解决
这是我们需要解决的问题:
比如说有一个领导,旁边有他的秘书小李,有一天,领导给小李说:"小李啊,没茶叶了,你给我买点上好茶叶去,如果买回来了,我就给你涨工资,如果没买上,就去站墙根去。"
在上述问题中,小李需要有一个买茶叶的方法,但是买完茶叶回来呢?小李将茶叶买回来后的事件是领导来定义的,比如,"买回来了,我给你涨工资",这是领导制定的,小李只是执行这个方法罢了,
所以,小李需要有三个方法,一个是成功的将茶叶买回来的事件方法,一个是没有吧茶叶买回来的事件方法,还有一个是自己买茶叶的方法,而这些事件方法,都可以直接写在买茶叶的方法中
一般回调都是用于耗时操作,而耗时操作时候回调的方法一般都可以看做事件(Event)。例如在网上请求的耗时操作,成功后需要回调的请求成功事件(getSuccessEvent),有人讲义在Blcoks的引用的后面都加上Block,我不是很建议这样做。我建议在所有的回调事件的后面都加上Event,而不是Blcok,这样更易于自己和别人理解和维护
下面上代码
小李是Worker类的对象,其.m文件为;
#import "Worker.h" @implementation Worker /** 去买茶叶的方法 回调事件: buySuccessEvnet : 如果购买茶叶成功后会回调的事件 buyFailEvnet : 如果购买茶叶失败后回回调的事件 */ -(void) buyTeaAndSetBuySuccessEvent:(void(^)()) buySuccessEvnet setBuyFailEvent:(void(^)()) buyFailEvnet{ NSLog(@"正在买茶叶"); //模拟买茶叶的耗时操作 [NSThread sleepForTimeInterval : 3.0 ]; NSLog(@"我买茶叶成功啦"); //如果调用者实现了此blocks的话,则回调 if (buySuccessEvnet) { buySuccessEvnet(); } } @end
.h文件为:
#import <Foundation/Foundation.h> @interface Worker : NSObject{ } /** 去买茶叶的方法 回调事件: buySuccessEvnet : 如果购买茶叶成功后会回调的事件 buyFailEvnet : 如果购买茶叶失败后回回调的事件 */ -(void) buyTeaAndSetBuySuccessEvent:(void(^)()) buySuccessEvnet setBuyFailEvent:(void(^)()) buyFailEvnet; @end
我们就暂时不写领导的Leader类了,暂时将我们当做一个领导,直接在主方法中调用小李的方法
下面是调用的方法(可以写在ViewController中的viewDidLoad方法里面):
- (void)viewDidLoad { [super viewDidLoad]; Worker *xiaoLi = [[Worker alloc] init]; //调用小李的买茶叶的方法 [xiaoLi buyTeaAndSetBuySuccessEvent:^{ NSLog(@"小李你做的不错,这月给你涨工资"); } setBuyFailEvent:^{ NSLog(@"小李你成天想什么呢,去墙角站着!"); }]; }
正在买茶叶
三秒钟后,出现:
我买茶叶成功啦
小李你做的不错,这月给你涨工资
我们可以仔细分析一下上述代码,上述代码并没有在一个直接定义一个块变量,而是在方法中直接声明
这里有一个方面需要注意,即是如果这个方法是我的,我在这个方法里面声明了一个块,那我只需要调用即可(实际上这种调用即是回调)
而如果我调用了这个方法,这个方法需要传入块,那么我需要实现这个块,虽然这个块我没有定义变量,我只需要将这个块的body写上即可
这就是直接使用Block进行回调的例子,也是我们经常使用在项目中的Block的方法
③.定义并使用blocks来进行回调 :
可能有人要问,既然我可以直接使用blocks来进行回调,那么我可以先定义一个blocks,然后在使用这个blocks进行回调吗,当然可以,但是非常不建议这样做,这样做的话有两个问题
1.代码更多,不利用维护,理解
2.可以会出现空指针的问题,即回调为空
下面上这种方式写的代码:
worker的.h文件:
#import <Foundation/Foundation.h> @interface Worker : NSObject{ } /** 去买茶叶的方法 */ -(void) buyTea; //如果购买茶叶成功后会回调的事件 //记得要使用copy属性 参考: http://blog.sina.com.cn/s/blog_6dce99b10101bsum.html @property (copy) void (^buySuccessEvnet)(void); //如果购买茶叶成功后会回调的事件 @property (copy) void (^buyFailEvnet)(void); @end
.m文件:
#import "Worker.h" @implementation Worker /** 去买茶叶的方法 */ -(void) buyTea{ NSLog(@"正在买茶叶"); //模拟买茶叶的耗时操作 [NSThread sleepForTimeInterval : 3.0 ]; NSLog(@"我买茶叶成功啦"); //如果调用者实现了此blocks的话,则回调 if (self.buySuccessEvnet) { self.buySuccessEvnet(); } } @end
主方法中进行调用:
Worker *xiaoLi = [[Worker alloc] init]; //调用小李的买茶叶的方法 [xiaoLi buyTea];
只会出现这些结果:
正在买茶叶
我买茶叶成功啦
正确调用的代码为:
Worker *xiaoLi = [[Worker alloc] init]; [xiaoLi setBuySuccessEvnet:^{ NSLog(@"小李你做的不错,这月给你涨工资"); }]; [xiaoLi setBuyFailEvnet:^{ NSLog(@"小李你成天想什么呢,去墙角站着!"); }]; //调用小李的买茶叶的方法 [xiaoLi buyTea];
则结果为:
正在买茶叶
我买茶叶成功啦
小李你做的不错,这月给你涨工资
所以说,不是很建议使用这种方法,代码复杂且不够直接,很容易使用者感到困惑
版权声明:本文为博主原创文章,未经博主允许不得转载。
标签:delegate protocol block blocks ios
原文地址:http://blog.csdn.net/wingsofpiano/article/details/47111839