我遇到了ARC和块的问题,但已经解决了问题。不幸的是,我不知道到底发生了什么,并想了解更多关于我的情况。
最初,我有代码执行此操作
for(__block id<Foo> object in objects) {
foo download:someParm
success:^{
object.state = StateNewState;
}
];
}
这导致保留不平衡。访问对象并且据说已经解除分配时发生崩溃。我编写了一个实现并使用“copy”属性来创建successBlock属性的类,该属性保存了传递给下载函数的success参数的块。我用以下
替换了代码for(id<Foo> object in objects) {
foo download:someParm
success:^(id<Foo> successObject){
successObject.state = StateNewState;
}
];
}
没有更多的解除分配的对象错误,但我还没有运行仪器来检查我是否没有泄漏。一些如何使用__block导致对象被释放太多次,我无法弄清楚为什么。我将继续研究这个问题的原因,但我认为这对其他人来说是一个有趣的问题。
我想值得注意的是,对象数组是一个自动释放的数组,它是在我在本文前面写下的代码的行中创建的。不要认为这很重要,但我想我只是在那里。我在这篇文章中提到的代码不是确切的代码,因为我正在使用它来工作,并且那里有一堆绒毛。但是for循环中没有创建其他对象。
当应用程序崩溃时,它运行下载,然后运行回调,顺便说一句,我正在使用ASIHttp。当我再次尝试下载时,它会运行并且不会调用回调,因为对象已被释放并且委托是无效的。在此之后,当一个字典访问对象时,该字典包含指向我们崩溃的对象的指针。
答案 0 :(得分:4)
在块中使用实例变量将导致该对象 本身要保留。如果您希望覆盖此行为 特定的对象变量,您可以使用__block存储标记它 类型修饰符。
如果您使用ARC,则会在复制块并稍后释放时自动保留和释放对象变量。
因此,如果您不使用__block
,我认为您会发现您的变量正在为您保留。例如,这似乎对我有用:
NSMutableArray *array = [[NSMutableArray alloc] init];
// add two custom objects to that array
[array addObject:[[MyObject alloc] initWithText:@"One" number:1]];
[array addObject:[[MyObject alloc] initWithText:@"Two" number:2]];
[array addObject:[[MyObject alloc] initWithText:@"Three" number:3]];
// now replace the text field in each of the three objects with the word "Done"
for (MyObject *object in array)
{
[self blockTestInvocation:^{
NSLog(@"%s %@", __FUNCTION__, [NSDate date]);
object.text = @"Done";
}];
}
我发现当__block
同步调用传递的块时,blockTestInvocation
的存在或不存在会产生重大影响,但是当我将其设置为异步调用块时(在我的数组和对象以其他方式被释放之后),__block
的缺失确保了对象被保留,从而防止了被发送到解除分配的实例的可怕消息&#34; (也没有泄漏)。但是对于__block
,该对象不会被保留,因此可以在代码块尝试引用它时释放它。
答案 1 :(得分:1)
两件事:
1)有些事情并不能说明你所描述的内容。你说你把这些对象放在一个自动释放的数组中,这个数组可能是为了运行循环而临时存储的。然后你的块回调在这些对象上设置一些状态,除非其他东西也保留它们,否则这将是毫无意义的。所以你的问题在于其他东西 - 无论创造什么,这些对象应该在它们需要的时候保留它们 - 大概足以观察状态变化。如果是,您将不会收到EXC_BAD_ACCESS错误。
2)你的循环中不需要__block
限定符。它基本上告诉编译器你的块可能会为该引用分配一个新对象,因此它需要取消引用该变量。但你的阻止不会这样做。您只是向对象发送消息。如果不使用__block
限定符,则块将获取值的const副本 - 该值是指向对象的指针。然后,当您执行object.state = StateNewState
时,您将向该指针处的对象发送setState:newState
消息。所以这应该工作正常:
for(id<Foo> object in objects) {
foo download:someParm
success:^{
object.state = StateNewState;
}
];
}