使用弱引用来检查对象是否已取消分配,在Objective-C中

时间:2012-10-16 13:59:11

标签: iphone objective-c

我正在使用ARC 有时候我写了下面的代码来断言一个对象应该被释放:

__weak weakVariableOrProperty = someObject;
....

someObject = nil;
// or someObject = anotherObject;
....

if (weakVariableOrProperty) {
    @throw [NSException exceptionWithName:NSInternalInconsistencyException reason:@"Object not deallocated" userInfo:nil];
}

例如,我使用此代码检查在创建新视图控制器之前是否取消分配视图控制器。

我认为弱变量或弱属性在最后一个强变量或属性设置为nil或其他对象后立即设置为

此代码正如我预期的那样工作到现在。

使用弱变量或属性来检查对象是否被释放是一种常用的技术? 这段代码可能会在将来引起问题吗?

3 个答案:

答案 0 :(得分:2)

  

我认为弱变量或弱属性在最后一个强变量或属性设置为nil或其他对象后立即设置为nil

这不完全正确,因为对象可以自动释放。在这种情况下,最后一个强引用可能会消失,但实例的引用计数将保持为正。在这种情况下,__weak引用将不会nil - 直到自动释放过程发生。

  

使用弱变量或属性来检查对象是否被解除分配是一种常用的技术?

我非常怀疑这种技术已经获得了很大的普及,因为ARC对于目标C来说是一个相对较新的东西。但是,该技术似乎是有效的。

  

此代码可能会在将来导致问题吗?

这很难猜测,因为ARC Specification没有对nil的时间进行任何具体保证 - 因为规范允许编译器优化{retain的序列。他们发送给ARC对象的1}}和release条消息。

答案 1 :(得分:1)

您的解释代码将容易出现竞争状况。

在评估weakVariableOrProperty条件后,if中的对象可以被释放(因为它仅由弱引用引用)。为避免这种情况,请引入一个普通变量,将其设置为weakVariableOrProperty并将其检查为nil

那就是说,正如@dasblinkenlight所说的那样,在某个对象消失的时候完全投注很难。在引用计数系统中,您不知道还有什么内容。你检查后它可能会消失。你应该能够足够地约束你的环境,以至于你知道系统不会让事情变得棘手,但自动释放和弱引用都会使事情变得复杂。

解决这个问题的最好方法就是拥有明确定义的对象生命周期:视图控制器不会永远存在,你明确告诉它们会消失等等。

答案 2 :(得分:0)

所以我尝试使用这种技术来确保始终在后台线程上释放对象。我的一些课程的[dealloc]体重中等,可能需要很长时间(10秒),这会使主线程稍微冻结。

我决定将所有这些重型对象添加到数组中,然后才在主线程上释放它们,然后在后台线程上通过该数组将它们从数组中删除。想法是数组会保持retainCount活着,直到它可以从后台线程上的数组中删除,然后我可以保证[dealloc]的成本不会发生在主线程上。

要做到这一点,我有以下代码:

while([objectsToDealloc count] && /* other conditions to prevent infinite loop */){
    __weak id ref = [objectsToDealloc lastObject];
    [objectsToDealloc removeLastObject];
    @synchronized(ref){
        // synchronising on ref will retain it if possible.
        // so if its still around,that means we didn't dealloc it
        // like we were asked to.
        // so insert it back into our array. once the object is deallocd
        // it won't be able to be synchronized, because the weak ref will
        // be nil
        if(ref){
            [objectsToDealloc insertObject:ref atIndex:0];
        }
    }
}

这个想法是,如果数组不包含最后一个引用(或者如果对象上有待处理的自动释放等),那么弱引用就不会出来。然后我会对对象进行@synchronize - 同步块将保留+释放正在同步的任何对象 - 这将确保ref在该块期间保持活动状态。如果它是零,那么它已被解除分配。如果它不是nil,那么我应该将它添加回数组并稍后再回来查看。

在过去几周内使用此代码进行测试后,我不建议使用此策略来检查已解除分配的对象。我还没有找到确切的原因,但很少有对象会dealloc但是ref也不会是nil,所以我将把一个无效的对象添加回数组。

我只在调试器中捕获过一次,虽然我有几次崩溃日志。你可以看到下面的“nil”最终出现在我的数组中,即使上面的代码应该防止它。

nil inside an NSArray

同样,我建议不要使用这种技术来检测对象何时/是否解除分配,而是集中精力澄清对象图和关系。