0

我遇到了 ARC 和块的问题,但已经解决了这个问题。不幸的是,我不知道到底发生了什么,并且想更多地了解我的情况。

最初,我有这样做的代码

for(__block id<Foo> object in objects) {
    foo download:someParm
         success:^{
            object.state = StateNewState; 
         }
    ];
}

这导致了保留的不平衡。当一个对象被访问并且据说已经被释放时,就会发生崩溃。我编写了一个实现并使用“复制”属性创建一个成功块属性的类,该属性保存了传递给下载函数成功参数的块。我用以下代码替换了代码

for(id<Foo> object in objects) {
    foo download:someParm
         success:^(id<Foo> successObject){
            successObject.state = StateNewState; 
         }
    ];
}

没有更多的释放对象错误,但我还没有运行工具来检查我是否没有泄漏。一些如何使用 __block 导致对象被释放太多次,我不知道为什么。我将继续研究这个问题的原因,但我认为这对你们其他人来说是一个有趣的问题。

我想可能值得注意的是 objects 数组是一个自动释放的数组,它是在我在本文前面写下的代码的行中创建的。不要认为这很重要,但我想我只是在那里度过。我在这篇文章中的代码不是确切的代码,因为我正在使用它来工作并且那里有一堆绒毛。但是在 for 循环中没有创建其他对象。

当应用程序崩溃时,它会运行下载,然后运行回调,顺便说一下,我正在使用 ASIHttp。当我尝试再次下载时,它会运行并且不会调用回调,因为对象已被释放并且委托被取消。在此之后,当包含指向对象的指针的字典访问对象时,我们会崩溃。

4

2 回答 2

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对象被保留,从而防止可怕的“消息发送到释放的实例”(也没有泄漏)。但是使用__block,对象不会被保留,因此可以在代码块尝试引用它时被释放。

于 2012-05-30T02:43:56.900 回答
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; 
         }
    ];
}
于 2012-05-30T18:08:28.980 回答