转载自:http://www.cnblogs.com/xiaofeixiang/p/4666796.html

关于Block之前有一篇文章已经写过一篇文章Object-C-代码块Block回顾,不过写的比较浅显,不能体现出Block在实际开发中的重要性,关于Block的基础知识,可以参考之前的博客。在实际开发中Block在回调过程中的是非常适合开发使用,不管是苹果的官方的接口还是一些第三方库的接口中都用到了Block回调。很多情况下Block和GCD一起使用,最常见的场景的就是App去后台取数据的过程中是需要时间,数据取成功之后我们才能更新UI页面,这就是最常见的回调的方式,也可以通过Notification来做,如果是单个用Notification没问题,如果请求比较多的情况的,代码量会上一个级别。

Block回调

简单的Block写法,返回类型  Block名称  参数,基本上符合方法的写法,先看一个最简单的Block写法:

1
2
3
4
5
int  (^blockDemo)(int a,int b)=^(int a,int b){
    return a+b;
};
 
NSLog(@"BlockDemo的结果:%d",blockDemo(90,72));

最后的结果是162,简单明了,很容易看懂,现在我们先通过UITableView展示后台数据,效果如下:

ViewController中的代码,简单的实现了一下UITableView:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
- (UITableView *)tableView {
    if (!_tableView) {
        _tableView = [[UITableView alloc]
                      initWithFrame:CGRectMake(0, 64, CGRectGetWidth(self.view.bounds) - 10,
                                               CGRectGetHeight(self.view.bounds) - 64)
                      style:UITableViewStylePlain];
        _tableView.rowHeight = 40.0;
        _tableView.sectionHeaderHeight = 0.0;
        _tableView.sectionFooterHeight = 0.0;
        _tableView.dataSource = self;
        _tableView.delegate = self;
    }
    return _tableView;
}
 
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
    return [self.dataSource count];
}
 
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
    UITableViewCell  *cell=[[UITableViewCell alloc]init];
    cell.textLabel.text=[self.dataSource objectAtIndex:indexPath.row];
    return cell;
}

通过FEDataService中的fetchData取出数据:

1
2
3
4
-(NSMutableArray *)fetchData{
    NSMutableArray  *mutableArray=[[NSMutableArray alloc]initWithObjects:@"博客园",@"FlyElephant",@"http://www.cnblogs.com/xiaofeixiang",@"iOS技术交流群:228407086",nil];
    return mutableArray;
}

Controller中的调用:

1
2
self.dataService=[[FEDataService alloc]init];
self.dataSource=[self.dataService  fetchData];

当时从后台取数据是需要时间的,而且网络不一定能取出数据,这个时候就可以通过Block进行回调,在DataService中重新定义了一个fetchDataSource方法:

1
-(void)fetchDataSource:(void(^)(NSMutableArray *array,NSError *error))fetchDataBlock;

注意这里的Block传参的写法,fetchDataBlock相当于是参数名,前面的是类型,实现中加入了GCD

1
2
3
4
5
6
7
8
-(void)fetchDataSource:(void (^)(NSMutableArray *, NSError *))fetchDataBlock{
    dispatch_time_t  time=dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC*(int64_t)1.0);
    dispatch_after(time,dispatch_get_main_queue() , ^{
         NSMutableArray  *mutableArray=[[NSMutableArray alloc]initWithObjects:@"博客园",@"FlyElephant",@"http://www.cnblogs.com/xiaofeixiang",@"iOS技术交流群:228407086",nil];
        fetchDataBlock(mutableArray,nil);
    });
     
}

Controller中进行回调同样实现以上效果:

1
2
3
4
5
6
[self.dataService fetchDataSource:^(NSMutableArray  *array,NSError *error){
    if (!error) {
        self.dataSource=array;
        [self.tableView reloadData];
    }
}];

Block延伸

1.栈块,堆块和全局块

定义一个块的时候,其所占的内存区域是在栈中的,块只在定义它的那个范围有有效,我们可以先看一下下面的写法:

1
2
3
4
5
6
7
8
9
10
11
NSString  *string=@"博客园FlyElephant";
void  (^block)();
if ([string isEqualToString:@"iOS技术交流群:228407086"]) {
    block=^{
        NSLog(@"keso");
    };
}else{
    block=^{
        NSLog(@"http://www.cnblogs.com/xiaofeixiang");
    };
}

先定义了block,之后在判断语句中对block进行赋值,最终栈中保存两个块的内存,在判断语句之外调用block有可能会把分配给块的内存覆盖,最终造成的结果就是有的时候正确,被覆写的时候就会造成程序崩溃,解决上面问题的方式我们可以通过block从栈内存中通过copy存储在堆内存中,代码如下:

1
2
3
4
5
6
7
8
9
10
11
NSString  *string=@"博客园FlyElephant";
void  (^block)();
if ([string isEqualToString:@"iOS技术交流群:228407086"]) {
    block=[^{
        NSLog(@"keso");
    copy];
}else{
    block=[^{
        NSLog(@"http://www.cnblogs.com/xiaofeixiang");
    copy];
}

存储在堆中的块就变成了引用计算类型,当引用计数变成0在ARC的环境下的就会被系统回收,而栈中的内存是由系统自动回收的,所以第一段代码稳定性不能保证,还有一种是全局块,将全局块声明在全局内存中,编译期就已经确定,不需要每次用到的在栈中创建,全局块的拷贝是一个空操作,所以全局块不可能被系统回收。

2.通过typedef简化代码可读性

Block回调中我们发现传入一个块的对象写法有的时候看起来实在不是那么简单明了,我们可以通过typedef简化定义一个块:

1
typedef void  (^FetchBlock)(NSMutableArray  *dataSouce,NSError  *error);

DataService中方法就可以简化了不少:

1
-(void)fetchDataSourceSimple:(FetchBlock)block;

实现代码和之前的block实现一样:

1
2
3
4
5
6
7
-(void)fetchDataSourceSimple:(FetchBlock)block{
    dispatch_time_t  time=dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC*(int64_t)1.0);
    dispatch_after(time,dispatch_get_main_queue() , ^{
        NSMutableArray  *mutableArray=[[NSMutableArray alloc]initWithObjects:@"博客园",@"FlyElephant",@"http://www.cnblogs.com/xiaofeixiang",@"iOS技术交流群:228407086"nil];
        block(mutableArray,nil);
    });
}

Block 进阶的更多相关文章

  1. Objective-C中的Block(闭包)

    学习OC有接触到一个新词Block(个人感觉又是一个牛气冲天的词),但不是新的概念,不是新的东西.学过Javascript的小伙伴对闭包应该不陌生吧~学过PHP的应该也不陌生,在PHP5.3版本以后也 ...

  2. Objective-C中的Block(闭包) (轉載)

    来源: 伯乐在线 - 青玉伏案 链接:http://ios.jobbole.com/83229/ 学习OC有接触到一个新词Block(个人感觉又是一个牛气冲天的词),但不是新的概念,不是新的东西.学过 ...

  3. iOS开发 - OC - block的详解 - 基础篇

    深入理解oc中的block 苹果在Mac OS X10.6 和iOS 4之后引入了block语法.这一举动对于许多OC使用者的编码风格改变很大.就我本人而言,感觉block用起来还是很爽的,但一直以来 ...

  4. Python进阶----进程之间通信(互斥锁,队列(参数:timeout和block),), ***生产消费者模型

    Python进阶----进程之间通信(互斥锁,队列(参数:timeout和block),), ***生产消费者模型 一丶互斥锁 含义: ​ ​ ​ 每个对象都对应于一个可称为" 互斥锁&qu ...

  5. iOS开发——UI进阶篇(九)block的巧用

    前面有提到通知.代理.kvo等方法来协助不同对象之间的消息通信,今天再介绍一下用block来解决这个问题 接着前面的例子 这里将功能在复述一遍 我把用block和通知放在一起比较,当然代理和kvo如何 ...

  6. iOS进阶面试题----Block部分

    1 什么是block 对于闭包 (block),有很多定义,其中闭包就是能够读取其它函数内部变量的函数,这个定义即接近本质又较好理解.对于刚接触Block的同学,会觉得有些绕, 因为我们习惯写这样的程 ...

  7. iOS进阶——可取消的block

    + (id)performBlock:(void (^)())aBlock onQueue:(dispatch_queue_t)queue afterDelay:(NSTimeInterval)del ...

  8. idea 插件的使用 进阶篇

    CSDN 2016博客之星评选结果公布    [系列直播]零基础学习微信小程序!      "我的2016"主题征文活动   博客的神秘功能 idea 插件的使用 进阶篇(个人收集 ...

  9. django 进阶篇

    models(模型) 创建数据库,设计表结构和字段 使用 MySQLdb 来连接数据库,并编写数据访问层代码 业务逻辑层去调用数据访问层执行数据库操作 import MySQLdb def GetLi ...

随机推荐

  1. Servie之前台Service

    public class MyService extends Service { public static final String TAG = "MyService"; pri ...

  2. POJ 3417 Network

    每条额外的边加入到图中,会导致树上一条路径成环,假设没有其余边,那么要将新图分成两部分,如果想删一条成环路径上的边,那么必须把这条额外边也删除. 因此每条额外边加入时,只需将环上的边+1.最后看看每条 ...

  3. iOS自定制tabbar与系统的tabbar冲突,造成第一次点击各个item图片更换选中,第二次选中部分item图片不改变

    可以选择是使用自定制的还是系统的,如果使用自定制的,就使用以下方法即可隐藏系统的uitabbarButton,从而使item恢复正确 //隐藏UITabBarButton -(void)viewWil ...

  4. mysql 发生系统错误1067的解决方法

    解决方法如下: 1.先删除mysql服务 控制面板->管理工具->服务,先停止mysql服务 开始->运行->输入cmd->sc delete mysql 服务删除 2. ...

  5. thinkphp的目录结构设计经验总结1

    ---恢复内容开始--- 用thinkphp开发了好些项目了:最近准备抽空写一些经验总结: 希望能给刚开始接触tp的童鞋们提供一些开发的方案:少走一些弯路:少踩一些坑: 这些绝对都是些精华干货:耐着性 ...

  6. CDN技术详解及实现原理

    CDN技术详解 一本好的入门书是带你进入陌生领域的明灯,<CDN技术详解>绝对是带你进入CDN行业的那盏最亮的明灯.因此,虽然只是纯粹的重点抄录,我也要把<CDN技术详解>的精 ...

  7. RESTful架构2--架构详解

    转自:RESTful架构详解 1. 什么是REST REST全称是Representational State Transfer,中文意思是表述(编者注:通常译为表征)性状态转移. 它首次出现在200 ...

  8. Beanstalkd

    摘要by ck:beanstalkd  和  kafka的本质区别是什么? Beanstalkd,一个高性能.轻量级的分布式内存队列系统,最初设计的目的是想通过后台异步执行耗时的任务来降低高容量Web ...

  9. OpenCV——运用于pixels war游戏

    // The "Square Detector" program. // It loads several images sequentially and tries to fin ...

  10. flash 右键菜单隐藏与修改

    来源:http://blog.sina.com.cn/s/blog_7264c84401014fmd.html import flash.ui.ContextMenu;import flash.ui. ...