ios - 了解NSAutoreleasePool

标签 ios objective-c nsautoreleasepool

我有一个应用程序,在iPhone 4s上使用相机时会收到内存警告。我先缩放图像,然后再使用它。

+ (UIImage*)simpleImageWithImage:(UIImage*)image scaledToSize:(CGSize)newSize
{

// Create a graphics image context
UIGraphicsBeginImageContext(newSize);

// Tell the old image to draw in this new context, with the desired
// new size
[image drawInRect:CGRectMake(0,0,newSize.width,newSize.height)];

// Get the new image from the context
UIImage* newImage = UIGraphicsGetImageFromCurrentImageContext();

// End the context
UIGraphicsEndImageContext();


// Return the new image.
return newImage;
}

我读到你应该从这里使用NSAutoreleasePool http://wiresareobsolete.com/2010/08/uiimagepickercontroller/

所以我修改了这样的代码:
+ (UIImage*)simpleImageWithImage:(UIImage*)image scaledToSize:(CGSize)newSize
{
//http://wiresareobsolete.com/2010/08/uiimagepickercontroller/

NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

// Create a graphics image context
UIGraphicsBeginImageContext(newSize);

// Tell the old image to draw in this new context, with the desired
// new size
[image drawInRect:CGRectMake(0,0,newSize.width,newSize.height)];

// Get the new image from the context
UIImage* newImage = UIGraphicsGetImageFromCurrentImageContext();

// End the context
UIGraphicsEndImageContext();

[newImage retain];

[pool release];

// Return the new image.
return newImage;
}

内存警告消失了。我没有在单独的线程上调用它。
NSAutoreleasePool 在做什么?我只是不明白。

我可以在本地NSAutoreleasePool中保留对象吗?

释放NSAutoreleasePool后可以使用保留的对象吗?

重要的问题: NSAutoreleasePool的这种特定用法如何帮助我的应用程序占用内存,从而不会收到内存警告?

最佳答案

首先,您应该使用@autoreleasepool块而不是NSAutoreleasePool对象;后者已经过时了。前者更好,因为当您离开该块的作用域时,它会自动清空池,而无需您自己明确地做。

自动释放池仅在其作用域内记住已“自动释放”的内容,并在耗尽该池时将其释放。 “自动释放”对象就像释放它,但是被推迟;从内存管理的角度来看,它需要一个强大的引用,并将其“转移”到池中,因此该池现在对对象具有强大的引用,而您却没有。在ARC之前的版本中,如果某个方法(其名称不是以newcopy开头)需要返回在该函数期间创建的对象,则几乎必须将其自动释放。通过将其放到池中,可以保证调用函数可以接收到该对象。在您的代码中,UIGraphicsGetImageFromCurrentImageContext()可能会返回一个自动释放的对象。

自动释放池仅在池末排空。池中的对象在池的持续时间内保持 Activity 状态(因为它们实际上已被池“拥有”)。这意味着,如果池持续时间很长,并且其中有很多东西会自动释放,那么将阻止许多对象被释放,这很可能是不好的。

例如,说一次运行函数会自动释放一个对象(即UIGraphicsGetImageFromCurrentImageContext()返回的对象)。然后,如果您在一个循环中运行函数100,000次,那么100,000个对象将留在内存中,因为它们被放到还没有机会耗尽的同一个池中。但是,如果您在循环的每个迭代中放入另一个级别的池,则它将在每次迭代结束时耗尽,从而阻止了对象的建立。

至于第二段代码,将自动释放池放入simpleImageWithImage:方法中确实会捕获UIGraphicsGetImageFromCurrentImageContext()的自动释放。但是,您还有另一个问题,因为为了从simpleImageWithImage:方法本身返回图像对象,您需要自动释放!

您编写的方法违反了内存管理规则。您的方法返回一个保留对象,调用者必须记住该对象才能释放。但是, call 者不知道基于名称的信息。根据命名约定,唯一可以返回保留实例的方法是那些名称以allocretainnewcopymutableCopy开头的方法。您的方法不以任何这些方法开头,因此它必须返回一个非保留实例。由于您拥有该对象(通过保留它),因此必须进行平衡释放或自动释放。您无法释放它,因为由于没有其他强大的引用,它可能导致对象可能被释放,因此只能自动释放它。

但是,如果要再次自动释放它,则除非在drawInRect:UIGraphicsGetImageFromCurrentImageContext()内部自动释放很多东西,否则您在此处添加自动释放池并没有完成任何事情。

关于ios - 了解NSAutoreleasePool,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27328930/

相关文章:

objective-c - UITextView 在我旋转它之前不显示文本

ios - Unity iOS 构建错误 : duplicate symbols when using Firebase Unity SDK + Google VR SDK for Unity

ios - 更正 SCNCamera 的 "Field of View"

objective-c - NSMutableArray 中的本地搜索

objective-c - 帮助解决编译器警告 : Initialization from distinct Objective-C type when types match

iPhone 自动释放池和分配

ios - 放4个导航栏按钮

ios - 动画 block 中 UIView 的旋转和设置中心有时不起作用

ios - 使用ARC,每个线程都没有自动释放池是致命的吗?

ios - 在 posix 线程上创建自动释放池