我有一组动画,需要按顺序操作,并在每一步完成各种检查。因为集合的大小是在运行时确定的,所以我希望使用递归调用...但是我无法让它在“块”范例内运行。
无论我是否使用
预先声明了块,结果都是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
}
}
非常感谢任何帮助 谢谢!
答案 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已经过时,所有内容都保留在副本中。