ios(3)-Block
2015-11-10 10:10
417 查看
Block
block语法
^(函数返回类型)(函数参数列表,参数,...){表达式}一个栗子:
^void (int a,int b){ printf(@"%d",a+b); };
block概念
block包含的两个方面的内容 :Block执行的代码,这是在编译的时候已经生成好的;
一个包含Block执行时需要的所有外部变量值的数据结构。 Block将使用到的、作用域附近到的变量的值建立一份快照拷贝到栈上。
Quote from OneV's Den 引用自喵神
block就 是一个代码块,但是它的神奇之处在于在内联(inline)执行的时候(这和C++很像) 还可以传递参数。同时block本身也可以被作为参数在方法和函数间传递 这就给予了block无限的可能。
与函数的区别
block不仅实现函数的功能,还可以携带函数的执行环境对闭包内的函数变量做一种保护措施,让其他函数无法访问该变量
为什么要有block
让函数作为参数调用,而且当它作为参数的同时还可以传递参数 (如何理解可以传递参数:是不是说block作文参数传递的时候自身带的参数还是说携带的执行环境?)iOS下用block + GCD来在程序中实现非阻塞式执行耗时任务
让内部函数访问函数外的在同一范围下的变量;
如何使用
typedef long (^Sum)(int,int); Sum sum = ^void (int a,int b){ printf(@"%d",a+b); } //调用block sum(1,2);
可能遇到的问题以及解决方法
在ARC当中,block会对传进来的参数进行retainretain cycle问题的根源在于Block和obj可能会互相强引用,互相retain对方,这样就导致了retain cycle,最后这个Block和obj相互持有,谁也释放不了谁。比如:
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url]; [request setCompletionBlock:^{ NSString* string = [request responseString]; }];
解决办法:ARC中用__weak属性修饰
MRC中用__block属性修饰
注意:
MRC中__block是不会引起retain;
但在ARC中__block则会引起retain。ARC中block会自动retain传进来的参数,所以不用担心在block执行之前该变量被释放的问题。
ARC中应该使用__weak或__unsafe_unretained弱引用。
__weak只能在iOS5以后使用。
block只能访问外部变量,不能对外部变量进行改变,如果要修改,有两种方法:
需在该变量上 添加属性__block 当我们给block访问外部变量的时候,实际上是在栈上copy了该参数,在编译的时候已经确定该外部变量的值,所以对其更改无效。对引用的外部变量添加__block属性,是在定义(注意是定义,不是运行)时,局部变量base当前值被copy到栈上,作为常量供Block使用。
使用实例变量
block在内存中的三种位置 llvm&clang
BlkSum blk1 = ^ long (int a, int b) { return a + b; }; NSLog(@"blk1 = %@", blk1);// blk1 = <__NSGlobalBlock__: 0x47d0> int base = 100; BlkSum blk2 = ^ long (int a, int b) { return base + a + b; }; NSLog(@"blk2 = %@", blk2); // blk2 = <__NSStackBlock__: 0xbfffddf8> BlkSum blk3 = [[blk2 copy] autorelease]; NSLog(@"blk3 = %@", blk3); // blk3 = <__NSMallocBlock__: 0x902fda0>
NSStackBlock 位于栈空间,在函数返回后block无效
NSGlobalBlock 没有访问block之外的变量,位于text代码段
NSMallocBlock 当block作为对象加入到NSArray 或者 NSDictionary中时,会在堆上开辟一段空间复制block
[?]为什么blk1类型是NSGlobalBlock,而blk2类型是NSStackBlock?
blk1和blk2的区别在于,blk1没有使用Block以外的任何外部变量,Block不需要建立局部变量值的快照,这使blk1与函数没有任何区别,从blk1所在内存地址0x47d0猜测编译器把blk1放到了text代码段。blk2与blk1唯一不同是的使用了局部变量base,在定义(注意是定义,不是运行)blk2时,局部变量base当前值被copy到栈上,作为常量供Block使用。执行下面代码,结果是203,而不是204。
int base = 100; base += 100; BlkSum sum = ^ long (int a, int b) { return base + a + b; }; base++; printf("%ld",sum(1,2));
Block中使用__block修饰的变量时,将取变量此刻运行时的值,而不是定义时的快照。执行下面代码,结果是204
__block int base = 100; base += 100; BlkSum sum = ^ long (int a, int b) { return base + a + b; }; base++; printf("%ld",sum(1,2));
Apple所推荐的block使用范围包括以下几个方面:
枚举——通过block获取枚举对象或控制枚举进程
View动画——简单明了的方式规定动画
排序——在block内写排序算法
通知——当某事件发生后执行block内的代码
错误处理——当错误发生时执行block代码
完成处理——当方法执行完毕后执行block代码
GCD多线程——多线程控制
block就是一个结构体
参考:
[1] http://tanqisen.github.io/blog/2013/04/19/gcd-block-cycle-retain/
[2] http://onevcat.com/2011/11/objc-block/
相关文章推荐
- 转:iOS9的新特性以及适配方案
- iOS 获取手机的型号,系统版本,软件名称,软件版本
- 使用ARM汇编破解iOS程序基础知识分享
- iOS -实例变量
- IOS 实现录音PCM转MP3格式(边录音边转码)
- iOS之渐变虚化背景图片
- iOS之CocoaPods使用步骤
- iOS学习笔记 自定义cell并且文本自适应高度
- iOS-autolayout 学习
- iOS开发中文件的上传和下载功能的基本实现
- iOS_Runtime_OC对象在堆内存中开辟内存的大小
- iOS完整学习路线图
- iOS --弹框1
- 小技巧3-iOS 获取当前系统时间
- iOS --自定义xib
- iOS 获取文件的目录路径的几种方法 [转]
- (NO.00003)iOS游戏简单的机器人投射游戏成形记(三)
- (NO.00003)iOS游戏简单的机器人投射游戏成形记(三)
- (NO.00003)iOS游戏简单的机器人投射游戏成形记(三)
- (NO.00003)iOS游戏简单的机器人投射游戏成形记(二)