在animateWithDuration中块完成内的递归调用?

时间:2011-05-06 19:18:32

标签: iphone animation uiview enumeration objective-c-blocks

我有一组动画,需要按顺序操作,并在每一步完成各种检查。因为集合的大小是在运行时确定的,所以我希望使用递归调用...但是我无法让它在“块”范例内运行。

无论我是否使用

预先声明了块,结果都是EXEC_BAD_ACCESS
__block void (^myBlock)(BOOL) = ^(BOOL finished){ if (finished) [self nextStep];};

与否,如下面的代码片段所示。在调试时,似乎'self'变量确实有效。

NSEnumerator* stepEnumerator;

-(void) mainRoutine {
    stepEnumerator = [myArray objectEnumerator];
    [self nextStep];
}

-(void) nextStep {
    id obj;
    if ((obj = [stepEnumerator nextObject])) {
        // Do my checking at each location
        ....

        // we have another spot to move to
        [UIView animateWithDuration:animationDuration
                         animations:^{self.frame = newFrame;}
                         completion:^(BOOL finished){ if (finished) [self nextStep];}];
        }
    }
    else {
        // we are done, finish house cleaning
    }
}

非常感谢任何帮助 谢谢!

2 个答案:

答案 0 :(得分:5)

提出的问题的答案是,是的,块完成内的递归调用是有效的 @BillBrasky提出了一个关于阻挡范围的好点。我不知道是否需要这样做,因为我没有发现它是我的情况的问题。通过我的递归函数,在每次连续迭代中,一切似乎都能正常工作。

我最初编写并提交代码的核心问题是使用FastEnumerator。当你离开当前函数并冒险进入堆栈框架的另一个事件循环/新部分时,这肯定会丢失。我意识到,我更多地想到它可能会在幕后花费很多时间来使FastEnumeration工作,并且离开该方法会破坏设置是合乎逻辑的。

作为修复,我用一个简单的整数替换了NSEnumerator,然后我每次都通过递归函数递增。我不是这方面的忠实粉丝,因为它可能导致Out of Bounds样式问题,而FastEnumerator不会,for (obj in array),但我不知道另一个解决方案。我想我会将其作为一个单独的问题发布......

更正后的代码:

int index;

-(void) mainRoutine {
    index = 0;
    if (index < [myArray count]) {
        [self nextStep];
    }
}

-(void) nextStep {
    // obtain the object from the array
    id obj = [myArray objectAtIndex:index++];
    // do my checking on the object
    ...

    [UIView animationWithDuration:animationDuration
                       animations:^{self.frame = [view frame];}
                      completions:^(BOOL finished) {
                          if (finished && index < [myArray count]) {
                              [self nextStep];
                          }
                          else {
                              // We are done, clean up
                              ...
                          }
                      }];
}

再次感谢@BillBrasky,您帮我指出了解决此问题的正确途径。我过于专注于递归,我对' self '对象的快速分析看起来很好,因为一个项目的除了都没问题。结合调试器打破了块,而不是实际的违规行,谁知道我会在没有看到真正问题的情况下盯着代码多久。

干杯。

答案 1 :(得分:2)

我也是新手,但我刚刚完成了类似的问题。在我的情况下,导致EXEC_BAD_ACCESS是因为已超出范围。我怀疑在第二次递归的某个时候,块被创建了一个奇数堆栈帧,因为它在另一个块内执行。

我的解决方案是将块保存在标记为copy的属性中,例如

@property (nonatomic,copy) BOOL (^callback)(DownloadProgress*);

这可以确保在原始块对象超出范围且GC已经过时,所有内容都保留在副本中。