【问题标题】:release and retain释放和保留
【发布时间】:2011-01-24 07:41:27
【问题描述】:

假设我做了以下事情(foo 从某个对象开始):

[foo release];
// STUFF with foo   
[foo retain];

只要我不重新分配 foo,在这结束时我仍然会拥有相同的 foo,对吗?在 //STUFF 期间我不会冒失去 foo 的风险,是吗?

我想我是在确保我对发布的理解是正确的。如果我释放 foo,它实际上不会消失,直到它的所有句柄都消失了。换句话说,foo 必须被分配给 //STUFF 中的某个其他对象,或者 foo 必须超出 //STUFF 中的范围(并且可能创建了一个新的 foo)才能获得实际的原始 foo要删除的对象,对吗?

编辑动机:

我想这样做的原因是,假设我有以下 switch 语句:

switch (test)
{
   case 1:
      foo = [A alloc];
      [foo inita];
      break;
   case 2:
      foo =  [B alloc];
      [foo initb];
      break;
   case 3: 
      [foo setupc];
      break;
   case 4:
      f = [D alloc];
      [foo initd];
      break;
}

在切换之前释放 foo 并在结束时保留它是有意义的。除了案例 3​​。所以,我在想如果可以安全地执行我建议的操作,它可能会使代码更简单。

当然,我可以在每个 alloc/init 周围放置一个释放/保留对,但这是很多重复的代码......

一个 [foo autorelease] 然后保留可能就可以解决问题。

【问题讨论】:

  • 如果您能在此处提供更多上下文,将会有所帮助。 foo 是一个实例变量吗?您是否假设 foo 在切换之前已经包含一个对象? (否则,为什么需要调用 -release?)此外,alloc 返回一个保留计数为 1 的实例。为什么需要额外调用来保留?我完全不清楚你在这里要做什么。
  • 测试的性质是什么?根据答案,可能会用多态行为替换开关。
  • @JLehr,test 是一个基于 mimetype 的 int。不同的类型是不同类型的文档... foo 是一个实例变量,它可能已经包含一个对象。 (因此发布)在案例 3 的实际代码中,有一个“if (foo==nil) foo = [C alloc];”在第 3 种情况下...我不确定是否需要保留。我想我的问题比我想象的要大......

标签: objective-c release retain


【解决方案1】:

不,是这样的:

-release 方法减少保留计数,然后检查它现在是否为零。如果保留计数为零,-release 会调用[self dealloc],这会导致对象立即被释放。因此,鉴于您的示例,在发送 -retain 消息之前发送 -release 并不是一个好主意,并且可能会导致您的应用崩溃。

根据您添加的 cmets,以下是另一种编写代码的方法,我认为该方法可以满足您的需求,同时避免代码重复:

Class class = Nil;

// Decide which class (if any) to use...
switch (test)
{
    case 1: class = [A class];  break;
    case 2: class = [B class];  break;
    case 3: class = foo == nil ? Nil : [C class]; break;
    case 4: class = [D class];  break;
}

// If a class was selected, create a new instance 
// and release the previous one...
if (class != Nil)
{
    [foo release];
    foo = [[class alloc] init];
}

请注意,这里不需要-retain,因为正如我之前提到的,+alloc 将保留计数设置为 1。

【讨论】:

    【解决方案2】:

    是的,您绝对 在引用计数(非 GC)环境中 STUFF 期间冒着“失败”的风险。如果您的第一个 -releasefoo 的引用计数减为 0,它将被释放。在这种情况下继续使用foo 会冒险进入未定义的行为,您几乎肯定会最终付出代价。也就是说,这里有龙。它可能在您(以及您调用的任何其他框架)在STUFF 期间不分配任何内存的情况下工作,这会覆盖foo 引用的分配实例 foo-dealloc 方法所指向的实例除了释放实例变量引用并破坏这些引用所占用的内存等之外,不会改变foo 的状态。在这种情况下,您的代码可能就像 foo 没有被释放一样工作,但这只是运气。

    在垃圾收集环境中,您是安全的。因为您持有对 fooSTUFF 的引用,并且因为 -release-retain 在 GC 环境中是无操作的,所以 foo 仍然有效。

    【讨论】:

      【解决方案3】:

      release 所做的只是减少每个对象都有的引用计数器。

      不过,我不确定你为什么要像你展示的那样releaseretain

      【讨论】:

        【解决方案4】:

        如果foo 的保留计数在该代码的开头变为零,它将被删除并停止工作。如果您想做类似的事情,请使用autorelease。根据文档,release 是垃圾收集环境中的无操作 - 也许这就是您的想法?

        【讨论】:

        • 实际上,当它的保留变为零时,您可以保证它会被完全清除。
        • @cobbal,这是真的。我不想在不查找的情况下明确地写出来。从那以后,我在文档中找到了我正在寻找的行,它与您所说的(以及我所期望的)一致。
        • @Brian,是的,autorelease 可以正常工作。但是你不想打电话给retain,以防万一3。你的代码看起来很奇怪——也许有更好的方法来做你正在尝试的事情?
        • 通常有更好的方法...我正在尝试将标准 foo 归类为 SuperClass,并且我正在将其初始化为子类 A、B、C 或 D 之一。如果它已经是 C,那么我不想创建一个新的,我只想保留我拥有的那个。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-04-13
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-11-17
        • 1970-01-01
        • 2012-12-06
        相关资源
        最近更新 更多