RetainCount可以在这个例子中使用吗?

时间:2012-04-05 16:03:25

标签: objective-c ios nsthread retaincount

RetainCount == BAD

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到1)如果是,则终止线程(quitDispatchThread将阻塞直到线程被终止)。

所以......

你可以依赖retainCount来查看它是否是一个吗?

通常人们会说要清除retainCount,因为你不知道那里是否有一些自动释放。但是,如果retainCount为1,那么我知道只有线程保持活着的事实我不必担心retainCount可能因某些自动释放等而关闭......

这段代码出了什么问题?

我准备删除它,但它实际上似乎有意义。其他对象不必知道我的类正在运行一个线程。其他对象可以安全retainrelease甚至autorelease拥有该线程的对象,而不必担心关闭线程,因为它会自行处理。

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

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

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

  

initWithTarget:选择器:对象

     

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

     
      
  • (id)initWithTarget:(id)target selector:(SEL)selector object:(id)argument
  •   
     

参数

     

     

发送者指定的消息发送到的对象。

     

选择

     

要发送给目标的邮件的选择器。这个选择器必须   只取一个参数,但不能有返回值。

     

参数

     

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

     

返回值

     

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

     

讨论

     

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

     

在执行分离线程期间保留对象target和argument。它们最终在线程时被释放   退出。

2 个答案:

答案 0 :(得分:6)

  

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

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

  

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

这是一个保留周期。这里的答案是找到一种方法来打破这个循环,而不是颠覆引用计数机制。当你的线程或拥有对象知道线程正在执行的工作已经完成(或者需要提前停止)时,必须在解除分配之前有一些点。

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

我不确定线程​​正在保留其创建者的情况(周期是一个非常明确的迹象表明某些你的所有权模式有问题) - 我猜你是'使用NSThreadinitWithTarget:...,目标是创建/拥有对象。这是标准MVC模式的混合 - 线程的所有者是“控制器”,线程本身(以及它运行的代码)更像是“模型”。

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

答案 1 :(得分:2)

不。你依赖的是一个抽象的实现,它公开地标记着“Keep Out”的标志。

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

另请参阅release的文档:

  

<强>释放

     

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

     

- (oneway void)release

     

<强>讨论

     

当引用计数达到0时,会向接收方发送dealloc消息。

     

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

如果您想确保您的程序在多个版本中正常运行,最好立即更改。