block在ARC/非ARC下的使用

来源:互联网 发布:凡科建站能做seo吗 编辑:程序博客网 时间:2024/05/17 03:57

一、block是不是对象

苹果的ObjectiveC官方文档中在“Working with Blocks”明确说明:

“ Blocks are Objective-C objects, which means they can be added to collections like NSArray or NSDictionary. ”

可见, Block是Objective C语言中的对象

苹果在block的文档中也提过这么一句:

“ As an optimization, block storage starts out on the stack—just like blocks themselves do. ”

Clang的文档中也有说明:

“ The initial allocation is done on the stack, but the runtime provides a Block_copy function ”

凭这一点,我们就可以回答剩下的两个问题。 Block对象与一般的类实例对象有所不同,一个主要的区别就是分配的位置不同,block默认在栈上分配,一般类的实例对象在堆上分配。

二、block可访问变量的范围

一个函数里定义了个block,这个block可以访问该函数的内部变量(当然还包括静态,全局变量),即block可以使用和本身定义范围相同的变量。
另外,block有截获局部变量的功能,什么叫截获局部变量呢?就是当block中访问局部变量时,会把这个局部变量拷贝到堆区。当block执行时,用到的还是这个拷贝到堆区的变量,不会受外面修改局部变量的影响。举个例子:

    int a = 100;    void(^blcokOne)() = ^{        NSLog(@"%d",a);    };    a = 200;    blcokOne();    NSLog(@"------>%d",a);

我们发现局部变量a的值确实是改变了,但是block中引用的a值却没有改变,就是上面的原理。
也正是因为有上面的原理,所以就有了block中不能修改局部变量的值(因为block中访问的局部变量是被拷贝到堆区的,可以认为是常量,当然就不可以修改了)。如果想修改,定义时要用__block修饰。即__block int a = 100。当然全局变量和静态变量是可以修改的。

三、Block存储域

根据存储域不同,block可以分为三种类型,分别是

- __NSStackBlock__  (存储在栈上)- __NSMallocBlock__  (存储在堆上)- __NSGlobalBlock__  (存储在全局数据区域)

没有引用局部变量或者声明为全局变量的Block为NSGlobalBlock,其他的基本上都是NSStackBlock。对NSStackBlock执行copy操作会生成NSMallocBlock。一般来说出问题的Block大部分都是NSMallocBlock,超过了NSMallocBlock的作用域NSMallocBlock就会销毁。

四、Block执行copy、retain的情形

无论是NSStackBlock,还是NSGlobalBlock,执行retain都不起作用。而NSMallocBlock执行retain引用计数+1。
在栈上调用copy那么复制到堆上,在全局block调用copy什么也不做,在堆上调用block 引用计数增加。
如果是非ARC环境,需要显式的执行copy或者antorelease方法。而当ARC有效的时候,实际上大部分情况下编译器已经为我们做好了,自动的将Block从栈上复制到堆上。包括以下几个情况:
1,Block作为返回值时
类似在非ARC的时候,对返回值Block执行[[returnedBlock copy] autorelease];
2,方法的参数中传递Block时
3,Cocoa框架中方法名中含有useringBlock等时
4,GCD相关的一系列API传递Block时。

0 0
原创粉丝点击