1

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

__weak weakVariableOrProperty = someObject;
....

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

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

例如,我使用这段代码在创建新的视图控制器之前检查视图控制器是否被释放。

我相信在最后一个强变量或属性设置为 nil 或其他对象之后,弱变量或弱属性立即设置为 nil。

到目前为止,这段代码正在按我的预期工作。

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

4

3 回答 3

2

I believe that weak variable or weak property is set to nil immediately after last strong variable or property was set to nil or another object.

This is not exactly true, because an object could be autoreleased. In this case, the last strong reference may be gone, but the reference count of the instance would remain positive. In cases like that, the __weak reference would not be nil-ed out until the autorelease process takes place.

Is using weak variable or property to check if object is deallocated a technique commonly used?

I seriously doubt that this technique has gained much popularity, because ARC is a relatively new thing to Objective C. However, the technique appears valid.

Is it possible that this code will cause problem in the future?

This is very hard to guess, because the ARC Specification does not make any specific guarantees about the timing of nil-ing out the references, and because the spec allows compilers to optimize sequences of retain and release messages that they send to ARC objects.

于 2012-10-16T14:25:36.403 回答
1

您的解释代码将容易出现竞争条件。

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

也就是说,正如@dasblinkenlight 所说,准确地押注一个物体何时会消失是很困难的。在引用计数系统中,您不知道还有什么在保留它。它可能会在您检查后消失。您应该能够对您的环境进行足够的限制,以使您知道系统不会将事情松懈,但是自动释放和弱引用都会使事情复杂化。

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

于 2012-10-16T14:56:53.363 回答
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,那么它就被释放了。如果它不是零,那么我应该将它添加回数组并稍后再检查。

在过去几周使用此代码进行测试后,我不能推荐这种策略来检查已释放的对象。我还没有找到确切的原因,但很少有对象会释放,但 ref 还不会是 nil,所以我会将一个无效的对象添加回数组中。

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

NSArray 中的 nil

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

于 2014-09-18T04:31:55.863 回答