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

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 指针变量就是为了无论在栈还是在堆,都能正确访问到该变量。






















没有更多推荐了,返回首页