【Objective-C高级编程】iOS与OS X多线程和内存管理(七) __block 从栈上复制到堆

来源:互联网 发布:物料编码软件 编辑:程序博客网 时间:2024/06/05 10:07
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堆引用计数增加



多次调用 copy 是否有问题:
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所持有。
当剩下的Block从栈复制到堆时,被复制的Block持有 __block 变量,并增加唉 __block 变量的引用计数。
故而 __block 变量中使用 __forwarding 指针变量就是为了无论在栈还是在堆,都能正确访问到该变量。






















1 0
原创粉丝点击