Block 进阶
转载自: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=^{ };} |
先定义了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=[^{ } 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 进阶的更多相关文章
- Objective-C中的Block(闭包)
学习OC有接触到一个新词Block(个人感觉又是一个牛气冲天的词),但不是新的概念,不是新的东西.学过Javascript的小伙伴对闭包应该不陌生吧~学过PHP的应该也不陌生,在PHP5.3版本以后也 ...
- Objective-C中的Block(闭包) (轉載)
来源: 伯乐在线 - 青玉伏案 链接:http://ios.jobbole.com/83229/ 学习OC有接触到一个新词Block(个人感觉又是一个牛气冲天的词),但不是新的概念,不是新的东西.学过 ...
- iOS开发 - OC - block的详解 - 基础篇
深入理解oc中的block 苹果在Mac OS X10.6 和iOS 4之后引入了block语法.这一举动对于许多OC使用者的编码风格改变很大.就我本人而言,感觉block用起来还是很爽的,但一直以来 ...
- Python进阶----进程之间通信(互斥锁,队列(参数:timeout和block),), ***生产消费者模型
Python进阶----进程之间通信(互斥锁,队列(参数:timeout和block),), ***生产消费者模型 一丶互斥锁 含义: 每个对象都对应于一个可称为" 互斥锁&qu ...
- iOS开发——UI进阶篇(九)block的巧用
前面有提到通知.代理.kvo等方法来协助不同对象之间的消息通信,今天再介绍一下用block来解决这个问题 接着前面的例子 这里将功能在复述一遍 我把用block和通知放在一起比较,当然代理和kvo如何 ...
- iOS进阶面试题----Block部分
1 什么是block 对于闭包 (block),有很多定义,其中闭包就是能够读取其它函数内部变量的函数,这个定义即接近本质又较好理解.对于刚接触Block的同学,会觉得有些绕, 因为我们习惯写这样的程 ...
- iOS进阶——可取消的block
+ (id)performBlock:(void (^)())aBlock onQueue:(dispatch_queue_t)queue afterDelay:(NSTimeInterval)del ...
- idea 插件的使用 进阶篇
CSDN 2016博客之星评选结果公布 [系列直播]零基础学习微信小程序! "我的2016"主题征文活动 博客的神秘功能 idea 插件的使用 进阶篇(个人收集 ...
- django 进阶篇
models(模型) 创建数据库,设计表结构和字段 使用 MySQLdb 来连接数据库,并编写数据访问层代码 业务逻辑层去调用数据访问层执行数据库操作 import MySQLdb def GetLi ...
随机推荐
- Windows进程间通信(下)
六.动态数据交换(Dynamic Data Exchange) 动态数据交换(DDE)是使用共享内存在应用程序之间进行数据交换的一种进程间通信形式.应用程序可以使用DDE进行一次性数据传输,也可以当出 ...
- JavaScript在智能手机上的应用-使用手机GPS定位用户所在城市
---------------------------- <script type="text/javascript" language="javascript&q ...
- javascript小数乘法精确率问题
做前端页面开发的经常会遇到数值的乘法计算,带小数位计算会出现值溢出的问题,如: JS里做小数的乘法运算时会出现浮点错误,具体可以测试一下: <script>alert(11*22.9)&l ...
- 如何创建自定义ASP.NET MVC5脚手架模板?
I'm using ASP.NET MVC5 and VS2013 I've tried to copy CodeTemplates folder from C:\Program Files (x86 ...
- c#操作oracle的通用类
using System;using System.Collections;using System.Collections.Generic;using System.Data;using Syste ...
- STM32的外部中断配置及使用
STM32的外部中断配置及使用 配置1:GPIO: 配置外部中断为输入模式: 配置2:EXTI: 配置外部中断线和触发模式: 配置3:NVIC: 配置外部中断源和中断优先级: 需要注意的是:RCC_A ...
- <c:if>替代
由于没有else, 由下面的替代 <c:choose> <c:when test="${usersession.hasPrivilegeByName('Case Delet ...
- 去掉input text后面的叉
如题 input[type=text]::-ms-clear{ display: none; } input::-webkit-search-cancel-button{ display: none; ...
- Windows下动态库的编译以及调用
1.MFC下生成动态库 1>显式调用 在.cpp文件里添加接口函数 int sum(int a,int b) { return a + b; } int sub(int a,int b) { r ...
- 第一次安装ubuntu要设置的东西
1. 安装网卡驱动 lscpi 查看网卡型号 根据型号找到驱动源码 下载下来并编译 安装 2. 编译安卓源码的时候出现jdk型号不对的情况 把/usr/bin/java 删除,就可以了.