【问题标题】:When to release the UIImage?什么时候发布 UIImage?
【发布时间】:2011-05-31 14:07:39
【问题描述】:

我使用下面的代码来绘制子图

UIImage* subIm = getSubImage( large, rect );
[subIm drawInRect:self.bounds];

其中getSubImage定义如下

    UIImage* getSubImage(UIImage* uim, CGRect rc){
      CGImageRef imref  = CGImageCreateWithImageInRect(uim.CGImage, rc); 
      UIImage*   sub = [UIImage imageWithCGImage:imref];
      CGImageRelease(imref);
        NSLog(@"subimage retainCount=%d", [sub  retainCount]); // is 1
      return sub;
   }//getSubImage

代码正确吗?

“CGImageRelease”imref 是否安全?

有子“CGImageRetained”imref 吗?

我应该释放 subIm(如果我这样做会出错)吗?

subIm 是否包含在 autorelease-pool 中,如果包含,我怎么知道?

一般来说,可以检查一个对象是否包含在自动释放池中(用于调试目的)?

【问题讨论】:

  • 不要不要致电retainCount。返回的数字通常没有意义。

标签: iphone ios memory-management cgimage autorelease


【解决方案1】:

不要调用 -retainCount

retain count返回的数字是对象的绝对retain count。可能有很多你无法控制的保留,因为它们是框架的实现细节。有总是更好的方法来验证代码的内存管理。

保留计数应仅视为增量;如果您使保留计数增加,则必须使其减少。

给定:

UIImage* getSubImage(UIImage* uim, CGRect rc){
  CGImageRef imref  = CGImageCreateWithImageInRect(uim.CGImage, rc); 
  UIImage*   sub = [UIImage imageWithCGImage:imref];
  CGImageRelease(imref);
    NSLog(@"subimage retainCount=%d", [sub  retainCount]); // is 1
  return sub;
}//getSubImage

imageWithCGImage: 返回一个自动释放的对象。保留计数无关紧要,因为 imageWithCGImage: 可能在内部做任何可能影响保留计数的事情——缓存等。

get* 是 Cocoa 编程中使用的一种奇怪模式。你只是没看到那么多。

我建议如下:

- (UIImage *) subImage: (UIImage *) anImage inRect: (CGRect) aRect
{
      CGImageRef imageRef  = CGImageCreateWithImageInRect(anImage.CGImage, aRect); 
      UIImage*   subImage = [UIImage imageWithCGImage: imageRef];
      CGImageRelease(imageRef);
      return subImage;
}

【讨论】:

  • @ragnarius "get" 通常在函数调用者对其负责(释放等)时使用,因此在这种情况下,它似乎是错误的,并且乍一看会使维护该代码的任何人感到困惑。
  • @drunknbass "get" 是相反的——它返回的是接收者拥有的东西,而不是调用者。 “new”或“copy”或“alloc”返回代表调用者隐式保留的项目。查看 CoreFoundation API 以获取示例; CFURLCopyPath() 返回一个新的 CFStringRef,调用者必须释放它,但 CFArrayGetValueAtIndex() 只返回一个不需要调用者管理的项目。
  • 根据c.crap.ps/3n6N,您可以在传入可以变异/修改的变量的函数上使用 get 前缀。实际上,我见过很多人以不同的方式使用它,但大多数人最终都得到了一个没有自动释放的对象。
【解决方案2】:

内存管理有一个命名约定。 所有 Cocoa 代码都遵循这个规则:

Basic Memory Management Rules

我强烈建议您阅读本文档并遵守规则。命名规则也是 Cocoa 的一部分。

来自参考文档:

您拥有您创建的任何对象。你 使用方法“创建”对象 其名称以“alloc”开头或 “新”或包含“副本”(例如, alloc、newObject 或 mutableCopy)。

您必须放弃对 完成后拥有的物品 跟他们。您放弃所有权 通过向对象发送释放 消息或自动释放消息 (自动释放在更多讨论 “自动释放”中的详细信息)。在可可 术语,放弃所有权 因此,一个对象通常是 称为“释放”一个对象。

Core Foundation 框架的 C 函数也有类似的规则。然而,没有这种类似自动释放的东西。如果你想用 C 函数制作 Objective-C 对象,你必须澄清文档中的所有内容。

这可能对您有所帮助: imageWithCGImage and memory

【讨论】:

  • +1 好的,我“拥有”imref 对象,因此我调用了 CGImageRelease。我不“拥有”子对象,因此我不调用 release,我可能会得出结论它已经在 autoReleasePool 中。
  • @ragnarius 完全正确。 :) 一旦你真正将这些简单的所有权规则内化,内存管理就变得很多容易了。
【解决方案3】:

SubIm 被注册到 AutoRelease Pool 中,因为这个对象实际上是由类方法 imageWithCGImage 创建的,并且规则是类方法创建的实例应该总是返回自动释放的实例。

代码是正确的,虽然我不明白你为什么使用 C 语法而不是 Obj-C 语法来定义你的函数

【讨论】:

  • 感谢您的这条规则,它会有所帮助!我仍然想知道 sub 是否有“CGImageRetained”imref...文档只说 imref 没有被缓存...
  • 我认为它保留了它,你应该释放它。我不知道为什么在 CGImageRelease 之后 retainCount 仍然是 1 并且可能是 CGImageRelease 添加到释放池..我不知道!可能在发布之前和之后检查?
  • 嗯,它是子图像的retainCount,如果它在AutoRelease池中,它应该是1。我不知道如何检查 imref 的retainCount,因为它不是objective-c 对象。
  • CGImageCreateWithImageInRect 创建一个对象,你负责释放它。如果你然后从中创建一个自动发布的 uiimage,你可以(并且应该)释放 cgimageref(就像你一样)。
  • 最终,你的 CGImageRef 的保留计数是多少并不重要——你创建了它,因此你必须释放它。如果 UIImage 想要保留它,那么 UIImage 有责任通过保留或复制它来做到这一点,而不是你的。例如,UIImage 可能复制该项目,这意味着您的实例将泄漏您不要释放它。
【解决方案4】:
  CGImageRelease(imref);
    NSLog(@"subimage retainCount=%d", [sub  retainCount]); // is 1
  return sub;

因为您的方法没有关键字 alloc、retain、copy...,所以您必须在返回 UIImage 之前自动释放它。但是 UIImage 的工厂方法已经为您做到了。请注意,即使您自动释放子,保留计数仍然是 1

【讨论】:

  • 发送alloc消息的方法需要释放或自动释放对象。在工厂方法的情况下,就是发送alloc 的方法,所以这就是发送autorelease 的方法。也就是说,不要担心其他类的实现——你自己的职责已经明确规定,你需要做的就是遵循它们。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-01-04
  • 2019-05-15
  • 1970-01-01
  • 2010-12-04
  • 2010-11-18
相关资源
最近更新 更多