使用模块和ARC是造成“消息发送到释放实例”错误(Using blocks and ARC is c

2019-09-17 14:29发布

我曾与ARC和块有问题,但已经解决了这个问题。 不幸的是我不知道究竟是怎么回事,想更多地了解我的情况。

本来,我有这样做的代码

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

这造成了一个不平衡保留。 当一个对象被访问,被认为是已经释放时发生崩溃。 我写了实现和使用“复制”属性来创建其保存传入下载功能的成功参数块successBlock属性的类。 我取代了代码与此有以下

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

没有更多的释放对象错误,但我还没有遇到仪器检查,如果我没有泄漏。 一些如何使用__block导致该对象被释放的次数太多了,我想不通为什么。 我会继续我的研究,对这一问题的原因,但我认为这会是你们想想其余一个有趣的问题。

我想这可能是值得注意的是,对象数组是在我继续在这个职位之前写下来的代码行创建一个autoreleased数组。 不要以为它会重要,但我觉得还是通过那里。 我把这个职位的代码是不是确切的代码,因为我用这个工作和那里面有一堆绒毛。 但是,有一个在正在创建的循环中没有其他物体。

当应用程序崩溃,它运行下载并运行后回调,我使用ASIHttp的方式。 当我尝试重新下载,运行,回调不叫,因为对象已释放和委托nil'ed。 在此之后,当对象是由包含一个指向对象偶们的字典访问。

Answer 1:

该模块编程主题说:

块中使用实例变量将导致自身被保留的对象。 如果你想覆盖这个行为对于特定的对象变量,您可以用__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 ,对象不被保留,并且因此可以通过代码块试图引用它的时间被释放。



Answer 2:

两件事情:

1)东西并不了解你所描述什么积少成多。 你说你在一个autoreleased数组,这大概是运行循环的目的临时存储将这些对象。 那么你的回调块上设置这些对象,这将是毫无意义的,除非另外还保留了他们一些状态。 所以,你的问题就出在其他的东西 - 无论创建这些对象应该留住他们,而这需要他们 - 足够长大概观察状态变化。 如果是这样,你就不会越来越EXC_BAD_ACCESS错误。

2)你不需要__block在循环预选赛。 它基本上是告诉你的块可能分配一个新的对象来表示参考编译器,所以它需要取消引用变量。 但是,你的块没有做到这一点。 你只是发送消息的对象。 如果你不使用__block预选赛中,你的块将采取价值的常拷贝-该值的一个指针对象。 然后,当你做object.state = StateNewState ,你发送一个setState:newState那个指针消息的对象。 所以这应该很好地工作:

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


文章来源: Using blocks and ARC is causing a “message sent to deallocated instance” error