【Objective-C高级编程】iOS与OS X多线程和内存管理(七) __block 从栈上复制到堆
2014-03-22 08:48
501 查看
typedef int (^blk_t)(int); blk_t func ( int rate ) { return ^(int count){ return rate*count; }; }
以上返回配置在栈上的Block的函数,虽然当作用域废弃后,栈上的Block也会被废弃。但是通过对应的ARC的编译器可转为如下:
blk_t func (int rate) { // 生成处于栈上的Block blk_t tmp = &__func_block_impl_0 (__func_block_func_0, &__func_block_desc_0DATA, rate); // 复制到堆上 tmp = objc_retainBlock(tmp); // 注册到 autoreleasepool 中,然后返回该对象 return objc_autoreleaseReturnValue(tmp); }
因为ARC处于有效的状态,blk_t tmp 实际上与附有__strong修饰符的 blk_t __strong tmp 相同。
而 objc_retainBlock 函数实际上就是 Block_copy 函数。
① 向方法或者函数的参数中传递 Block 时需要手动实现 copy 方法。
以下情况不必手动复制,因为该函数中已经适当的复制了传递过来的参数:
① Cocoa 框架的方法且方法名中含有 usingBlock 等时;
② Grand Central Dispatch 的API;
例如: 使用NSArray 类的 enumerateObjectUsingBlock 实例方法以及 dispatch_async 函数时,不用手动复制;
- (id)getBlockArray { int val = 10; return [[NSArray alloc] initWithObjcets: ^{NSLog(@“blk0:%d” ,val) ;}, ^{NSLog(@“blk1:%d”,val) ;}, nil]; } id obj getBlockArray (); typedef void (^blk_t)(void); blk_t blk = (blk_t)[obj objectAtIndex:0]; blk();
以上代码运行时会发生异常。这是由于在getBlockArray 函数结束后,Block被废弃的缘故。
将Block 从栈上复制到堆上比较消耗cpu资源
- (id)getBlockArray { int val = 10; return [[NSArray alloc] initWithObjcets: [^{NSLog(@“blk0:%d” ,val) ;} copy] , [^{NSLog(@“blk1:%d”,val) ;} copy] , nil]; }
对于已配置在堆上的Block以及配置在程序的数据区域上的Block,调用copy方法又会如何?
类 | 设置对象的存储域 | 复制效果 |
_NSConcreteStackBlock | 栈 | 从栈复制到堆 |
_NSConcreteGlobalBlock | 程序的数据区域(.data区) | 什么也不做 |
_NSConcreteMallocBlock | 堆 | 引用计数增加 |
blk = [[[[blk copy] copy] copy] copy];
可解释为:
{ blk_t tmp = [blk copy]; blk = tmp; } { blk_t tmp = [blk copy]; blk = tmp; } { blk_t tmp = [blk copy]; blk = tmp; } { blk_t tmp = [blk copy]; blk = tmp; }
代码解析:
{ // 将配置在栈上的Block 赋值给变量blk中 blk_t tmp = [blk copy]; // 将配置在堆上的Block赋值给变量tmp中,变量tmp持有强引用的Block。 blk = tmp; // 将变量tmp 的Block 赋值为变量blk,变量blk 持有强引用的Block。 // 此时Block 的持有者有 blk 和 tmp } // 由于变量作用域结束,所以变量tmp 被废弃,其强引用失效。 // 由于Block 还被blk 持有,所有被废弃
Block 从栈复制到堆时堆 __block变量产生的影响
__block 变量的配置存储域 | Block 从栈复制到堆 的影响 |
栈 | 从栈复制到堆并被Block持有 |
堆 | 被Block持有 |
当剩下的Block从栈复制到堆时,被复制的Block持有 __block 变量,并增加唉 __block 变量的引用计数。
故而 __block 变量中使用 __forwarding 指针变量就是为了无论在栈还是在堆,都能正确访问到该变量。
相关文章推荐
- 【Objective-C高级编程】iOS与OS X多线程和内存管理(八) __block 从栈上复制到堆 截获对象 数组
- 【Objective-C高级编程】iOS与OS X多线程和内存管理(三) Block语法
- 【Objective-C高级编程】iOS与OS X多线程和内存管理(四) Block的实现
- 【Objective-C高级编程】iOS与OS X多线程和内存管理(六) __block 说明符
- 【Objective-C高级编程】iOS与OS X多线程和内存管理(九) Block 循环引用
- Objective-C 高级编程:iOS与OS X多线程和内存管理
- Objective-C高级编程 iOS与OS X多线程和内存管理 读书笔记(一)
- block 知识点 ---- Objective-C 高级编程 iOS 与 OS X 多线程内存管理 学习笔记
- 读书笔记:Objective-C高级编程 iOS与OS X多线程和内存管理 ——(持续)
- 《Objective-C高级编程:iOS与OS X多线程和内存管理》读书笔记
- 《Objective-C 高级编程 iOS与OS X多线程和内存管理》 核心札记二
- 【Objective-C高级编程】iOS与OS X多线程和内存管理
- 《Objective-C 高级编程 iOS与OS X多线程和内存管理》 核心札记一
- 《Objective-C高级编程 iOS与OS X多线程和内存管理》学习笔记——第一章自动引用计数
- 《Objective-C 高级编程 iOS与OS X多线程和内存管理》 核心札记三
- 【Objective-C高级编程】iOS与OS X多线程和内存管理(二)
- 《Objective-C 高级编程 iOS与OS X多线程和内存管理》 核心札记二
- 读《Objective-C高级编程iOS与OS X多线程和内存管理》
- 内存管理原理----《Objective-C高级编程:iOS与OS X多线程和内存管理》读书笔记
- 【Objective-C高级编程】iOS与OS X多线程和内存管理(五) Blocks 截获自动变量值