4

RetainCount == 坏

retainCount是禁忌、不可靠、不可预测的,一般不应该使用。我没有在我的代码中的任何地方使用它,但是我在一个以一种有趣的方式使用的类中看到了它。

我有一个类运行一个无限期运行的线程,直到线程被取消。问题是线程增加了所有者的保留计数,在我的例子中是实例化它的类。所以,即使我用完了那个类,那个实例仍然会挂起,除非管理我的类的人也有聪明的知识来关闭线程。这是一种解决方案,但这是我在代码中找到的。

- (oneway void)release
{
    // This override allows allows this object to be dealloced 
    // by shutting down the thread when the thread holds the last reference.
    // Otherwise, the object will never be dealloc'd
    if (self.retainCount == 2)
    {
        [self quitDispatchThread];
    }

    [super release];
}

这是一个聪明的解决方案,但我不知道该怎么想。它覆盖类上的释放并检查保留计数是否为 2。换句话说,它检查线程是否是唯一使我的对象保持活动状态的线程(因为保留计数即将从 2 减少到 1 ),如果是,它终止线程(quitDispatchThread将阻塞直到线程终止)。

所以...

你可以依靠retainCount来看看它是不是一个?

通常人们会说要远离,retainCount因为你不知道那里是否有一些自动释放。但是,如果retainCount 是一个,那么我知道只有线程保持它处于活动状态,并且我不必担心retainCount 可能由于某些自动释放等而关闭......

这段代码有什么问题?

我正要删除它,但它实际上似乎是有道理的。其他对象不必知道我的类正在运行线程。其他对象甚至可以安全retain地拥有线程的对象,而不必担心关闭线程,因为它会照顾自己。releaseautorelease

这段代码实际上感觉很干净,这让我感到惊讶。

编辑 :: NSThread 正在保留我的对象

我使用 NSThread 的事实增加了我的对象的保留计数。我的对象是 thetarget并且selector是线程运行的方法。

initWithTarget:选择器:对象:

返回使用给定参数初始化的 NSThread 对象。

  • (id)initWithTarget:(id)目标选择器:(SEL)选择器对象:(id)参数

参数

目标

选择器指定的消息发送到的对象。

选择器

要发送到目标的消息的选择器。此选择器只能接受一个参数,并且不能有返回值。

争论

传递给目标的单个参数。可能为零。

返回值

使用给定参数初始化的 NSThread 对象。

讨论

对于非垃圾收集的应用程序,方法选择器负责为新分离的线程设置一个自动释放池,并在它退出之前释放该池。垃圾收集应用程序不需要创建自动释放池。

对象目标和参数在分离线程的执行过程中被保留。当线程最终退出时,它们被释放。

4

2 回答 2

6

retainCount是禁忌、不可靠、不可预测的,一般不应该使用。

您可以依靠retainCountIFF 的值,您的对象不会通过任何对您不透明的代码,例如任何 Cocoa 框架。在实践中,这几乎是不可能实现的,因此发出警告。Cocoa 的内部可能会出于多种原因多次传递您的对象、保留、释放并将其放入自动释放池中,您不能在任何给定点依赖它的绝对值。

问题是线程增加了所有者的保留计数,在我的例子中是实例化它的类。

那是一个保留周期。这里的答案是想办法打破这个循环,而不是颠覆引用计数机制。当您的线程或拥有对象知道线程正在执行的工作已完成(或需要提前停止)时,在释放之前必须有某个时间点。

听起来拥有对象是客户端代码与线程正在执行的工作的接口。此拥有对象需要一个“立即关闭”方法,该方法需要在其所有者释放它之前被调用(并记录为“必须调用”) 。在该关闭方法中,您可以通过释放线程来中断循环。

我不确定线程​​保留了它的创建者是怎么回事(这个循环非常清楚地表明的所有权模型有问题)——我猜你正在使用NSThreadand initWithTarget:...,目标是创建/拥有对象。这有点混淆了标准 MVC 模式——线程的所有者是“控制器”,线程本身(及其运行的代码)更像是“模型”。

换句话说,控制器不应该包含线程的代码。我建议您将线程的代码分解为另一个对象以用作目标。然后控制器对象拥有线程本身和“工作”目标对象,它们都不拥有控制器。瞧,没有循环!

于 2012-04-05T16:47:30.070 回答
2

没有。您依赖于一个抽象的实现,该实现在其大门上公开标有“Keep Out”的标志。

只需使用您自己的内存和实现来管理您的依赖项。这可能包括一个 ivar 和/或用于完成/销毁阶段的方法。

另请参阅文档release

释放

减少接收者的引用计数。(必需的)

- (oneway void)release

讨论

当引用计数达到 0 时,接收方会收到一个 dealloc 消息。

您只需实现此方法来定义您自己的引用计数方案。这样的实现不应该调用继承的方法;也就是说,它们不应包含对 super 的发布消息。

如果您想确保您的程序在多个版本中都能正常运行,最好现在就更改它。

于 2012-04-05T17:09:24.140 回答