在discussion之后,我遇到了一个糟糕的访问问题;
循环有几个步骤:a,b,c,... x,y,z:
-(void)cycle:(float)delta{
[self stepA]
[self stepB]
// etc.
[self stepZ]
}
在某些时候,步骤x执行以下操作:
// IRQ is an NSMutableArray
// Self is a reference to the engine running the cycles
[IRQ addObject:^{ NSLog(@"hello! %@", self); } ];
稍后,步骤z将处理所有“延迟”呼叫:
for (int i = 0; i < [IRQ count]; i++){
void (^delayedCall)(void) = [IRQ objectAtIndex:i];
delayedCall();
}
[IRQ removeAllObjects];
结果:EXEC_BAD_ACCESS
现在,如果步骤x只添加一个没有对象引用的普通字符串,如下所示,步骤Z工作正常:
[IRQ addObject:^{ NSLog(@"hello!"); } ];
最后一次观察,如果同一步骤都向队列添加块并迭代队列以执行块,则不会出现问题。 就像对象的引用被“丢失”一样,因为步骤:方法被留下了?
我对这方面的了解不多,需要更多的帮助!
编辑: 詹姆斯,刚试过以下内容以避免引用cyle:
NSString *userName = @"James";
[IRQ addObject:^{ NSLog(@"hello %@", userName); } ];
它也会发生。您的解决方案将如何适用于此?
提前致谢!
答案 0 :(得分:3)
当您使用^{}
语法创建块时,它会在堆栈上创建。要长时间保持块(超出创建它的函数的范围),必须将块复制到堆中:
void (^ myBlock)(void) = ^ {
// your block code is here.
};
[IRQ addObject:[[myBlock copy] autorelease]];
如果使用ARC,请跳过-autorelease
消息。
答案 1 :(得分:3)
问题是在堆栈上创建了块对象。如果希望在声明它们的作用域被销毁之后使用,并且不为您复制块,则需要将块复制到堆中。
在这里,您将一个“向下堆栈”的对象传递给一个不知道块的方法。取代
[IRQ addObject:^{ NSLog(@"hello! %@", self); } ];
与
[IRQ addObject:[^{ NSLog(@"hello! %@", self); } copy]];
此时EXC_BAD_ACCESS
将消失。
但在大多数情况下,您无需复制块!几个例子:
-[NSArray sortedArrayUsingComparator:]
。+[UIView animateWithDuration:options:animations:completion:]
。答案 2 :(得分:0)
您传递的对象似乎是..在您的示例中:self
和userName
过早被释放。这不是我期望的块行为。正如我之前的回答,我预计问题是因为保留太多了!
作为测试,您可以尝试:
NSString *userName = [@"James" retain];
[IRQ addObject:^{ NSLog(@"hello %@", userName); } ];
这将是内存泄漏,但它有助于指示对象是否正在被释放。
这是由于“保留周期”导致块保留 self
而self
保留该块。
试试这个:
__block typeof(self) blockSafeSelfReference = self;
[IRQ addObject:^{ NSLog(@"hello! %@", blockSafeSelfReference); } ];
如果使用ARC,请使用__unsafe_unretained
代替__block
击>