您的位置:首页 > 移动开发 > IOS开发

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会对传进来的参数进行retain

retain 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/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: