5

我正在使用CAAnimation完成块(使用CAAnimationBlocks)在动画结束时提供处理,并且该完成块的一部分会修改动画CALayer。即使layer没有使用说明符声明,这也有效__block,因为对象指针保持不变,但是我确实将对象视为读/写。

Apple Guide中令我困扰的一个方面是:

__block 变量存在于变量的词法范围和在变量的词法范围内声明或创建的所有块和块副本之间共享的存储中。

鉴于layer是一个集合迭代器,在我看来,如果我使用说明符,它实际上会中断__block

这是有问题的代码:

for (CALayer *layer in _myLayers)   // _myLayers is an ivar of the containing object
{
    CAAnimationGroup *group = ...;
    ...
    group.completion = ^(BOOL finished)
    {
        [CATransaction begin];
        [CATransaction setValue:(id)kCFBooleanTrue
                         forKey:kCATransactionDisableActions];
        layer.position = [self _findPosition];
        [CATransaction commit];

        [layer removeAnimationForKey:@"teleportEffect"];
    };

    [layer addAnimation:group forKey:@"teleportEffect"];
}

我的实际问题是:我做得对吗(我的蜘蛛感觉很刺痛)。

编辑我还应该补充一点,我的应用程序使用 MRR,但是保留/释放没有问题,因为这些层本质上是静态的(它们的生命周期是包含的生命周期NSView)。此外,我似乎正在做指南中要避免的模式部分所说的我不应该做的事情,尽管(对我来说)不清楚为什么。

4

2 回答 2

4

__block变量在块(和封闭范围)内是可变的,并且如果任何引用块被复制到堆中,变量就会被保留。

我不认为在您的情况下您需要一个块变量,因为您正在更改layer块内对象的值,因为它属于_myLayers似乎是实例变量的数组,很难在之前释放对象执行的每个块......但是,您可以添加__block存储类型修饰符来保留对象,但如果您使用ARC,对象变量会在块被复制和稍后释放时自动保留和释放

于 2012-09-16T09:03:52.220 回答
1

编辑:

至于您对您提到的反模式的关注,我认为在两个反模式示例中,关键点是变量声明和分配给它的“块文字”具有不同的范围。以for那里提出的案例为例:

void dontDoThis() {
  void (^blockArray[3])(void);  // an array of 3 block references

  for (int i = 0; i < 3; ++i) {
    blockArray[i] = ^{ printf("hello, %d\n", i); };
    // WRONG: The block literal scope is the "for" loop
  }
}
  1. blockArray在整个方法体内可见;

  2. for循环中,您创建一个块;块是一个对象(内存中的一些存储)并且有一个地址;作为对象的块具有“堆栈本地数据结构”(来自上面的参考资料),即当您进入方法时它被分配在堆栈上;

  3. “块文字”被视为for循环局部变量的事实意味着可以在每次连续迭代中重用存储;

  4. 块地址分配给blockArray元素;

  5. 当您退出for循环时,blockArray将包含可能不再存在和/或在每个步骤中已被覆盖的块的地址,具体取决于编译器对在for范围内创建的数据结构的堆栈操作。

您的情况不同,因为您的局部变量也在范围for内,并且在范围之外将不可见。

呈现为反模式的案例与此类似:

 {
 int array[3];

 for (int i = 0; i < 3; ++i) {
    int a = i;
    array[i] = &a;
    // WRONG: The block literal scope is the "for" loop
 }

很有可能,范围a内的变量for只会在堆栈上分配一次,然后在循环的每次迭代中重用。原则上,a(一份)在循环之外仍然存在(我不确定,实际上,应该检查 C 标准),但很明显,该代码的含义并不真正明智。

旧答案:

__block 变量存在于变量的词法范围和在变量的词法范围内声明或创建的所有块和块副本之间共享的存储中。

我认为这可以更好地理解为:__block变量的词法范围和所有块(根据上述定义)将共享该变量的相同存储。因此,如果一个块(或原始词法范围)修改了变量(我在这里指的是指向对象的变量),那么所有其他块都可以看到该更改。

鉴于此,声明变量的一个效果__block是,在非 ARC 情况下,它指向的对象不会被传递到的每个块自动保留(对于 ARC,保留也对__block变量进行) .

无论是使用 ARC 还是不使用 ARC,__block当您想要更改变量值并希望所有块都使用新值时,都需要使用说明符。想象一下,您有一个块来初始化您的_myLayersivar:在这种情况下,您需要将_myLayers变量作为__block变量传递到块中,以便可以修改它(相对于它的副本)。

在您的情况下,如果您不使用ARC,那么,这完全取决于layer执行块时指向的对象是否仍然存在。由于layer来自_myLayers,这将转换为_myLayers执行块时拥有的对象是否仍然存在。这个问题的答案通常是肯定的,因为我们所说的块是该层上动画的完成块。(例如,如果它是网络请求的完成块,情况会有所不同)。

希望这可以帮助。

于 2012-09-16T09:16:36.920 回答