【问题标题】:Objective-C Memory Management: crash on releaseObjective-C 内存管理:发布时崩溃
【发布时间】:2011-08-14 15:29:41
【问题描述】:

我是 Objective-C 的新手,似乎无法正确获取内存管理代码。我有以下代码:

Media* myMedia = [self.myMediaManager getNextMedia];

self.navigationItem.title = [self.myMediaManager getCategory];
[self.btnImage setImage:myMedia.imageFile forState: UIControlStateNormal];
[self.lblImage setText:myMedia.imageLabel];

//[myMedia release];

如果我取消注释以上行,我的应用程序会崩溃。实例化 myMedia 时是否需要做一些特别的事情?

编辑:

如果 myMediaManager 应该释放它,它什么时候会这样做。这是我的 getNextMedia 代码:

- (Media*) getNextMedia {

    DLog(@"Start");

    Media* nextMedia = [[Media alloc] init];

    [self setNextMediaIndex];

    if (self.mediaIndex > -1)
    {
        nextMedia = [mediaArray objectAtIndex: self.mediaIndex];
    }

    return nextMedia;
}

EDIT2:我修复了崩溃问题(我正在释放一个我不拥有的对象)。我仍然看到泄漏,似乎无法找到问题所在。

【问题讨论】:

  • 请张贴getNextMediagetCategory 的代码。否则,我们怎么知道?崩溃的发生是由于代码的各个部分的交互,而不仅仅是崩溃点上方的行。
  • 由于他没有从self中保留[self.myMediaManager getNextMedia],所以他不需要,它的retainCount仍然是一样的。
  • 不要在方法前面加上get;那应该只是nextMedia
  • 我阅读了有关内存管理的信息。所有的帖子都有助于我的理解。再次感谢!

标签: iphone objective-c memory-management


【解决方案1】:

只有您拥有的对象才能被释放。

如果您先newalloccopymutableCopyretain 对象,则可以release 对象。

由于[self.myMediaManager getNextMedia]; 中没有分配/复制/保留,因此您无法释放它。

【讨论】:

  • 是NARC(new、alloc、retain、copy、mutableCopy)需要对应的release。
【解决方案2】:

由于这里没有保留myMedia,所以不需要释放它。当 origin (self.myMediaManager) 释放它时,它会立即被销毁。

NSString *string = [[NSString alloc] init];
[string release]; // now we have to release the string, since we allocated it.

NSString *string = self.navigationItem.title;
// now we don't, since it's a property of `navigationItem` and we didn't retain it.

【讨论】:

    【解决方案3】:

    此时,由于您只是在学习,您可能应该刚开始将 ARC 与 XCode 的 iOS5 beta 版本一起使用。了解是件好事,但使用 ARC 会为您节省许多潜在的陷阱——当您学习到足以产生一些东西的时候,iOS5 将会出局。您仍然可以构建面向 iOS4 的应用程序,因此您仍然可以接触到很多人。

    【讨论】:

    • 一般我同意,但 ARC 并没有取消它;只是隐藏它。您仍然需要小心处理核心基础对象。此外,您需要了解在访问 self 的属性时可能会导致保留循环的块等位置保留和释放的内容,因为 self 是隐式保留的。
    • 谢谢,不知道 iOS 5 中会出现这种情况。听起来很有趣(如果它真的像 Apple 描述的那样有效)=)。
    • @Abizem - 在 ARC 为您所做的工作和编译器警告之间,它确实消除了很多可能的错误 - 尽管 self 保留在一个块中,但这最终只是一个潜在的问题在长期存在的块中,例如您将作为长期过程(如重复计时器)的回调传递的块。在你发布了类似视图控制器的东西之后,像动画完成这样的自我可能会被保留,但是当动画结束时它仍然会被释放,只是稍后......了解内存是个好主意,但是 ARC 太多了一天比一天轻松。
    • @Kendall - 不要误会我的意思 - 我认为 ARC 是一个巨大的优势。但是您刚刚展示了很多人没有的内存管理知识,他们认为 ARC 意味着他们不必考虑它。如果您因为任何这些事情而出现意外行为,您可以很快意识到问题所在。但对其他人来说——这意味着带着他们不理解的编译器错误/警告进入 SO。
    • @Abizem:我在使用 ARC 一段时间后的感觉是,为了进入 ARC 会混淆的情况,无论如何你必须对系统有足够的了解,否则你不会当你到达那里时自己感到困惑。这个人在能够更好地理解事情之前不会撞到 ARC 墙……
    【解决方案4】:

    内存管理的一般规则如下:

    对于每个retainalloccopynew,您需要调用releaseautorelease

    由于你没有调用任何这些,你不需要释放myMedia

    有关更多信息,请查看处理该主题的this other answer I posted。另外,由于您是 iOS 开发新手,我建议您也查看this answer

    【讨论】:

      【解决方案5】:

      这个更新的代码很可疑:

      Media* nextMedia = [[Media alloc] init];
      
      [self setNextMediaIndex];
      
      if (self.mediaIndex > -1)
      {
          nextMedia = [mediaArray objectAtIndex: self.mediaIndex];
      }
      

      根据if() 子句中的条件,您为nextMedia 分配一个新值,这使得您刚刚分配的值无法访问,即无法释放。

      此外,您不会保留从数组中获得的值,因此您也不应该释放它。但是如果if() 子句没有运行,你仍然有你分配的实例,应该释放它。

      这样不好。试试:

      Media* nextMedia = [[Media alloc] init];
      [self setNextMediaIndex];
      if (self.mediaIndex > -1)
      {
          [nextMedia release];
          nextMedia = [[mediaArray objectAtIndex: self.mediaIndex] retain];
      }
      

      你也可以这样做(我更愿意这样做):

      Media *nextMedia;
      [self setNextMediaIndex];
      if (self.mediaIndex > -1)
      {
          nextMedia = [[mediaArray objectAtIndex: self.mediaIndex] retain];
      }
      else
      {
          nextMedia = [[Media alloc] init];
      }
      

      现在您可以在不再需要时释放 nextMedia,而不会对保留计数产生任何歧义。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-02-07
        • 2020-01-27
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多