-
block类似与函数指针,与函数指针的区别在于其可以捕获(capture)其定义时作用域内的变量,当在其他位置调用时仍然可以使用。
-
block是一种Objective-C对象,其数据结构中存在isa指针,isa指针指向&_NSConcreteStackBlock或&_NSConcreteGlobalBlock。
-
block通常是在函数内定义的,此时block对象是在栈内分配的,若此block只在定义它的函数内使用,则block就会一直存在在栈中,当函数返回时,栈帧回退,定义的block也随之销毁。
- 当block需要在其定义时的函数外使用时,需要对其进行copy处理,copy的意义在于将block在堆中分配一份,这样当定义函数的栈帧回滚时,block仍然存在。
- copy操作可以向block对象发送-copy消息,也可使用C函数Block_copy(),释放操作则为-release或Block_release().
- 对block应该总是进行copy操作,因为对栈内分配的block拷贝会将其拷贝到堆中,对已经在堆中的block进行copy,则只会增加retain count,与retain操作相同。而对栈内分配的block进行retain操作则不会有任何影响。
- block之所以强大在于其可以捕获(capture)其引用的变量,包括局部变量,指针,Objective-C对象,全局变量,static变量等。
- 全局变量,static变量在block内是直接访问的,因为其内存区域一直存在。
- 对于引用的局部变量,block使用的方法是将局部变量拷贝到block内部,并声明为const,这样在block中将只能使用引用到局部变量的初始值,而不能进行修改。
- 局部指针变量被block const拷贝后仍然是指针,虽然指针本身是const的,但其指向的对象仍然是可以修改的。
- 如果想对引用的局部变量进行修改,可以在局部变量上使用__block标示符号,使用__block后的局部变量会以一种指针的方式被间接引用,引用其的block不会进行const copy,所有block、包含定义的函数内看到的__block局部变量都是同一份,任何block中对此变量进行修改都可以被其他block看到。在引用__block局部变量的block被从栈拷贝到堆时,__block变量也会被拷贝到堆中,所以__block变量在运行时是会变化的。
- 在block引用Objective-C对象时,会对Objecitive-C对象进行retain操作,当block销毁时再进行release操作。如果不想对引用的Objecitive-C对象做retain处理,则可以使用__block 标示要引用的Objecitive-C对象,这只适用于非ARC的代码中。在ARC代码中,即使用__block标示,在block引用时仍然会retain,这中情况下则需要使用__weak(iOS5)或__unsafe_unretained(iOS4,不支持weak的环境)。
- 如果在类方法中定义的block引用了类中的实例变量,则实际上是通过self以self->instanceVar的方式引用的,这是会对self做retain操作。这样会出现retain cycles,为了避免这中情况,一般会声明一个局部变量blockSelf,将self以__block或__weak,__unsafe_unretained的方式赋值给blockSelf,在block代码中则通过blockSelf引用类示例变量,这样可以避免retain cycles。
参考:
Block Implementation Specification
Language Specification for Blocks
Blocks Programming Topics
How blocks are implemented (and the consequences)
Blocks, Episode 2: Life Cycles
Programming with C Blocks
Using Blocks: Understanding the Memory Management Rules
Friday Q&A 2008-12-26 blocks
Friday Q&A 2009-08-14: Practical Blocks
Friday Q&A 2010-04-30: Dealing with Retain Cycles
Friday Q&A 2011-09-30: Automatic Reference Counting
Block的Retain Cycle的解决方法
IOS Blocks 详细介绍
最新推荐文章于 2023-03-05 20:45:57 发布