我有一个应用程序,在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之前的版本中,如果某个方法(其名称不是以new
或copy
开头)需要返回在该函数期间创建的对象,则几乎必须将其自动释放。通过将其放到池中,可以保证调用函数可以接收到该对象。在您的代码中,UIGraphicsGetImageFromCurrentImageContext()
可能会返回一个自动释放的对象。
自动释放池仅在池末排空。池中的对象在池的持续时间内保持 Activity 状态(因为它们实际上已被池“拥有”)。这意味着,如果池持续时间很长,并且其中有很多东西会自动释放,那么将阻止许多对象被释放,这很可能是不好的。
例如,说一次运行函数会自动释放一个对象(即UIGraphicsGetImageFromCurrentImageContext()
返回的对象)。然后,如果您在一个循环中运行函数100,000次,那么100,000个对象将留在内存中,因为它们被放到还没有机会耗尽的同一个池中。但是,如果您在循环的每个迭代中放入另一个级别的池,则它将在每次迭代结束时耗尽,从而阻止了对象的建立。
至于第二段代码,将自动释放池放入simpleImageWithImage:
方法中确实会捕获UIGraphicsGetImageFromCurrentImageContext()
的自动释放。但是,您还有另一个问题,因为为了从simpleImageWithImage:
方法本身返回图像对象,您需要自动释放!
您编写的方法违反了内存管理规则。您的方法返回一个保留对象,调用者必须记住该对象才能释放。但是, call 者不知道基于名称的信息。根据命名约定,唯一可以返回保留实例的方法是那些名称以alloc
,retain
,new
,copy
和mutableCopy
开头的方法。您的方法不以任何这些方法开头,因此它必须返回一个非保留实例。由于您拥有该对象(通过保留它),因此必须进行平衡释放或自动释放。您无法释放它,因为由于没有其他强大的引用,它可能导致对象可能被释放,因此只能自动释放它。
但是,如果要再次自动释放它,则除非在drawInRect:
或UIGraphicsGetImageFromCurrentImageContext()
内部自动释放很多东西,否则您在此处添加自动释放池并没有完成任何事情。
关于ios - 了解NSAutoreleasePool,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/27328930/