Block

Block究竟有哪些称呼和官方的解释。

匿名函数,块函数,块,block基本上他们都是同一个鸟人。

维基百科中说,Block是Apple Inc.为C,C++,以及OC 添加的新特性,使得它们可以用lambda表达式的语法来创建闭包.(lambda表达式既匿名函数表达式,闭包既是可以包含自由(未绑定到特定对象)变量的代码块,具体可以自己下去认真理解下)。我理解为block就是用匿名函数表达式创建的代码块.

闭包就是能够读取其它函数内部变量的函数

什么时候使用block.

Block除了能够定义参数列表、返回类型外,还能够获取被定义时的词法范围内的状态(比如局部变量),并且在一定条件下(比如使用__block变量)能够修改这些状态。此外,这些可修改的状态在相同词法范围内的多个block之间是共享的,即便出了该词法范围(比如栈展开,出了作用域),仍可以继续共享或者修改这些状态。通常来说,block都是一些简短代码片段的封装,适用作工作单元,通常用来做并发任务、遍历、以及回调。

block如何声明

[转载]iOS中block实际应用初探

int (*CFunc)(int a) 函数调用 int result = CFunc(10);

int (^BFunc)(int a) 函数调用 int result = BFunc(10);

block用法1

void (^myblocks) (void) = NULL;

myblocks = ^(void) {

NSLog(@"in blocks");

};

NSLog(@"before myblocks");

myblocks();

NSLog(@"after myblocks");

int (^myblocks2) (int a, int b) = ^(int a, int b) {

int c = a + b;

return c;

};

NSLog(@"before blocks2");

int ret = myblocks2(10, 20);

NSLog(@"after blocks2 ret %d", ret);

//此处如果不加__block会报错

__block int sum = 0;

int (^myblocks3) (int a, int b) = ^(int a, int b) {

sum = a + b;

return 3;

};

myblocks3(20, 30);

NSLog(@"sum is %d", sum);

对于这种用法,本人不才,基本没有在实际项目中用过.因为我的理解这实际意义不大(如果是这种简单的计算),唯一作用是提高程序的并发性.

回调是block一个重要的特性.

block回调是我在网络请求中用得最多的.

这里先用前辈在ASIHTTP中的block为例子.

定义block

#if NS_BLOCKS_AVAILABLE

typedef void (^ASIBasicBlock)(void);

typedef void (^ASIHeadersBlock)(NSDictionary *responseHeaders);

typedef void (^ASISizeBlock)(long long size);

typedef void (^ASIProgressBlock)(unsigned long long size, unsigned long long total);

typedef void (^ASIDataBlock)(NSData *data);

#endif

此定义可以是全局的block,

这里只用了上门定义的其中一个block为例,作为ASIHTTPRequest的一个属性.(意思是block可以作为一个对象的属性存在)

@interface ASIHTTPRequest : NSOperation {

ASIBasicBlock completionBlock;

}

//向外暴露一个接口  这里是为回调留一接口方法,其实也可以不用留

- (void)setCompletionBlock:(ASIBasicBlock)aCompletionBlock;

方法实现(这里用release是为开启arc)

@implementation ASIHTTPRequest

- (void)setCompletionBlock:(ASIBasicBlock)aCompletionBlock

{

[completionBlock release];

completionBlock = [aCompletionBlock copy];

}

这里是网络请求完成后的方法,在这里实现我们block的调用.

- (void)reportFinished

{

#if NS_BLOCKS_AVAILABLE

if(completionBlock){

completionBlock();

}

#endif

}

@end

如下,然后你可以在你请求网络的类实现中,实现网络请求并获取网络请求成功后的回调, 这里可以回传参数变量(我们这个例子block是回传的参数为void,--typedef void (^ASIBasicBlock)(void)--).在这里回传参数就是,上面说的参数共享,就象遍历数组,这样也许你更能理解

[arr enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {

}];

这里的obj 和idx 以及stop都可以为你在回调时候所用,就好比代理delegate回传参数一样.

ASIHTTPRequest *request = [self requestWithUrl:url];

//请求成功

[request setCompletionBlock:^{

switch (request.responseStatusCode) {

case RequestStatus_OK:

complete(request.responseString);break;

case RequestStatus_ErrorRequest:

failed(@"错误的请求");break;

case RequestStatus_NotFound:

failed(@"找不到指定的资源");break;

case RequestStatus_Error:

failed(@"内部服务器错误");break;

default:

failed(@"服务器出错");break;

}

}];

//请求失败

[request setFailedBlock:^{

failed(@"网络连接失败");

}];

这里的FailedBlock我们没有举例实现.



看了前辈的block实现,兄弟伙写是否有所理解?接下来看看,我写的一个block的简单用法.

第一种,接网络请求的block自己再次封装的方法.把block作为方法参数使用.

@interface JHttpRequest : NSObject

//异步Get请求

+ (ASIHTTPRequest *)asyncGetRequest:(NSString *)url complete:(void (^)(NSString *responseStr))complete failed:(void (^)(NSString *errorMsg))failed;

//异步Get请求带缓存

//异步Post请求

//异步Post上传图片

//异步下载请求

//生成异步请求对象

@end

//发送异步Get请求

+ (ASIHTTPRequest *)asyncGetRequest:(NSString *)url

complete:(void (^)(NSString *responseStr))complete

failed:(void (^)(NSString *errorMsg))failed{

ASIHTTPRequest *request = [self requestWithUrl:url];

[request setUserAgent:UserAgent];

[request setTimeOutSeconds:5.];

//请求成功

[request setCompletionBlock:^{

switch (request.responseStatusCode) {

case RequestStatus_OK:

complete(request.responseString);break;

case RequestStatus_ErrorRequest:

failed(@"错误的请求");break;

case RequestStatus_NotFound:

failed(@"找不到指定的资源");break;

case RequestStatus_Error:

failed(@"内部服务器错误");break;

default:

failed(@"服务器出错");break;

}

}];

//请求失败

[request setFailedBlock:^{

failed(@"网络连接失败");

}];

//开始请求

[request startAsynchronous];

return request;

}

下面是你需要调用网络接口的viewcontroller种对上面网络请求block方法的调用

[JHttpRequest asyncGetRequest:url complete:^(NSString *responseStr) {

if (responseStr) {

NSDictionary *getDic = [responseStr JSONValue];

if ([[getDic objectForKey:@"success"] boolValue]) {

//getDic 请求成功取得的json数据

}else{

faild([getDic objectForKey:@"msg"]);

}

}else{

faild(@"获取信息失败");

}

} failed:^(NSString *errorMsg) {

faild(errorMsg);

}];

综上例子所诉,block可以作为一个方法参数使用,能更方便地去取得回调数据.

第二种,把block作为类的属性来使用.

//定义一个block作为viewcontroler的一个属性.

@interface FirstViewController : UIViewController{

//定义一个blocks变量

void (^BarkCallback) (FirstViewController *thisDog, int count);

NSInteger barkCount;

}

@property(nonatomic , copy) void (^BarkCallback) (FirstViewController *thisDog, int count);

@end

其中void (^BarkCallback) (FirstViewController *thisDog, int count);thisDog count是参数.

@implementation FirstViewController

@synthesize BarkCallback;

- (void)viewDidLoad

{

[super viewDidLoad];

barkCount = 0;

//这里我们启动一个定时器方便回调看效果

[NSTimer scheduledTimerWithTimeInterval:10.0f target:self selector:@selector(updateTimer:) userInfo:nil repeats:YES];

}

-(void) updateTimer:(id) arg

{

barkCount ++;

if (BarkCallback) {

//调用从其他类传过来的BarkCallback

BarkCallback(self, barkCount);

}

}

@end

实现block

FirstViewController *viewController = [[FirstViewController alloc] initWithNibName:@"FirstViewController" bundle:nil];

viewController.BarkCallback = ^(FirstViewController *thisDog, int count) {

NSLog(@"count == %d", count);

};

把block作为类的属性来使用.还有一种表达方法.

typedef void (^BarkCallback) (FirstViewController *thisDog, int count);

@interface FirstViewController : UIViewController{

NSInteger barkCount;

}

@property (nonatomic, copy) BarkCallback completionHandler;

@end

@implementation FirstViewController

@synthesize completionHandler;

- (void)viewDidLoad

{

[super viewDidLoad];

barkCount = 0;

[NSTimer scheduledTimerWithTimeInterval:10.0f target:self selector:@selector(updateTimer:) userInfo:nil repeats:YES];

}

-(void) updateTimer:(id) arg

{

barkCount ++;

if (completionHandler) {

completionHandler(self, barkCount);

}

}

@end

实现block

FirstViewController *viewController = [[FirstViewController alloc]initWithNibName:@"FirstViewController" bundle:nil];

BarkCallback myab = ^(FirstViewController *thisDog, int count) {

NSLog(@"count == %d", count);

};

viewController.completionHandler = myab;

把block作为全局变量来使用.(无意间奇葩地自己创造出来的)

void (^ BarkCallback) (FirstViewController *thisDog, int count);

@interface FirstViewController : UIViewController{

NSInteger barkCount;

}

@end

@implementation FirstViewController

- (void)viewDidLoad

{

[super viewDidLoad];

barkCount = 0;

[NSTimer scheduledTimerWithTimeInterval:10.0f target:self selector:@selector(updateTimer:)userInfo:nil repeats:YES];

}

-(void) updateTimer:(id) arg

{

barkCount++;

if (BarkCallback) {

BarkCallback(self, barkCount);

}

}

@end

实现block

#import "FirstViewController.h"

BarkCallback  = ^(FirstViewController *thisDog, int count) {

NSLog(@"person do 1 222count %d", count);

};

最后,把block方法的参数来使用.(上面已经提到过)

@interface FirstViewController : UIViewController{

}

//向外暴露一个接口

-(void) setBark:( void (^) (FirstViewController *thisDog, int count) ) eachBark;

@end

@implementation FirstViewController

- (void)viewDidLoad

{

[super viewDidLoad];

barkCount = 0;

[NSTimer scheduledTimerWithTimeInterval:10.0f target:self selector:@selector(updateTimer:)userInfo:nil repeats:YES];

}

-(void) updateTimer:(id) arg

{

barkCount++;

}

-(void) setBark:(void (^)(FirstViewController *, int))eachBark

{

eachBark(self, barkCount);

//在这里我们直接把block回调了,其实一般不这样直接回调,一般情况是在某种动作完成后回调,比如网络请求,比如用户动作监听到以后回调,所以在这里我们可以简单改进下.

}

@end

方法改进

@interface FirstViewController : UIViewController{

//多定义个block变量指针

void (^BarkCallback) (FirstViewController *thisDog, int count);

}

//向外暴露一个接口

-(void) setBark:( void (^) (FirstViewController *thisDog, int count) ) eachBark;

@end

@implementation FirstViewController

- (void)viewDidLoad

{

[super viewDidLoad];

barkCount = 0;

[NSTimer scheduledTimerWithTimeInterval:10.0f target:self selector:@selector(updateTimer:)userInfo:nil repeats:YES];

}

-(void) updateTimer:(id) arg

{

barkCount++;

//在动作完成,或者监听到用户操作时,调用这个block。这里我们是用timer定时调用.

if (BarkCallback) {

BarkCallback(self, barkCount);

}

}

-(void) setBark:(void (^)(FirstViewController *, int))eachBark

{

//把实现类传过来的block指针付值给,我们定义的BarkCallback

BarkCallback = [eachBark copy];

}

@end

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,384评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,845评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,148评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,640评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,731评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,712评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,703评论 3 415
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,473评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,915评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,227评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,384评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,063评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,706评论 3 324
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,302评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,531评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,321评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,248评论 2 352

推荐阅读更多精彩内容