我有一个应用程序,在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()
可能会返回自动释放的对象。
自动释放池仅在池的末尾排出。池中的对象在池期间保持活动状态(因为它们实际上由池"拥有"(。这意味着如果池持续很长时间并且在其上自动释放很多东西,那么许多对象将被阻止被解除分配,这可能是不好的。
例如,假设函数的一次运行自动释放一个对象(即 UIGraphicsGetImageFromCurrentImageContext()
返回的对象(。然后,如果您在循环中运行函数 100,000 次,则 100,000 个对象将保留在内存中,因为它们被放入尚未有机会耗尽的同一池中。但是,如果在循环的每次迭代中放置另一个级别的池,它将在每次迭代结束时耗尽,从而阻止对象构建。
至于您的第二段代码,在您的 simpleImageWithImage:
方法中放置一个自动发布池确实会从 UIGraphicsGetImageFromCurrentImageContext()
中捕获自动发布。但是,您还有另一个问题,因为为了从simpleImageWithImage:
方法本身返回图像对象,您需要自动释放它!
您的方法(如所写(违反了内存管理规则。您的方法返回一个保留的对象,调用方必须记住释放该对象。但是,调用方根据名称不知道这一点。根据命名约定,唯一可以返回保留实例的方法就是那些名称以 alloc
、 retain
、 new
、 copy
和 mutableCopy
开头的方法。您的方法不以其中任何一个开头,因此它必须返回一个非保留实例。由于您拥有对象(通过保留它(,因此必须执行平衡释放或自动释放。您无法释放它,因为它会导致对象可能被释放,因为没有其他强引用,因此您只能自动释放它。
但是,如果您要再次自动发布它,则在此处添加自动发布池将一事无成,除非在drawInRect:
内部或内部UIGraphicsGetImageFromCurrentImageContext()
它们会自动发布很多东西。
您自己创建的 NSAutoreleasePool 只是在其区域中调用自动释放对象的释放方法,从 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
到 [pool release];
,
这里
UIImage* newImage = UIGraphicsGetImageFromCurrentImageContext();
newImage
是自动释放对象,[newImage release]
将在[pool release];
之后调用
如果没有[newImage retain];
newImage
将在[pool release];
后解除分配
- 您可以将对象保留在本地 NSAutoreleasePool 中。
- 您可以在释放 NSAutoreleasePool 后使用保留的对象。
- 使用
NSAutoreleasePool
释放临时内存。