我正在开发一个iPad绘画应用程序,用户可以在其中绘制N个图像,并拥有一个画廊将绘制的图像导出到不同的社交网络等。这里的问题是,当我使用iPad视网膜设备时,我收到了很多内存警告(最终导致崩溃(。我尝试了分析,并确定imageio_png_data,VM:CoreAnimation,VM:CG光栅数据等项目与非视网膜设备中的相同数据相比占用了大量内存。我知道这与图像加载有关,因为我正在应用程序中加载PNG,JPG文件格式等图像。
1.如何解决在视网膜显示设备中加载图像占用大量内存的问题
2.如何使应用程序避免imageio_png_data,VM:核心动画,VM:CG栅格数据等术语的大量内存消耗。
3.我得到了一些信息,像PVR纹理这样的图像可用于解决图像的内存相关问题。我是否可以将其集成到本机iOS应用程序中。(我也在运行时保存图像,因为它是一个绘画应用程序。
如果此选项适合您,您可以压缩低质量的图像。
UIImage *image = [UIImage imageNamed:@"image.png"];
NSData *imageData = UIImageJPEGRepresentation(image, 0.2); // 0.2 - quality
UIImage *lowQualityImage=[UIImage imageWithData:data];
如果您有许多映像不将它们存储在数组中,请使用 NSCache。
您应该在 UIImage 类别中实现此方法:
- (UIImage *)resizedImage:(CGSize)newSize
transform:(CGAffineTransform)transform
drawTransposed:(BOOL)transpose
interpolationQuality:(CGInterpolationQuality)quality {
CGRect newRect = CGRectIntegral(CGRectMake(0, 0, newSize.width, newSize.height));
CGRect transposedRect = CGRectMake(0, 0, newRect.size.height, newRect.size.width);
CGImageRef imageRef = self.CGImage;
// Build a context that's the same dimensions as the new size
CGContextRef bitmap = CGBitmapContextCreate(NULL,
newRect.size.width,
newRect.size.height,
CGImageGetBitsPerComponent(imageRef),
0,
CGImageGetColorSpace(imageRef),
CGImageGetBitmapInfo(imageRef));
// Rotate and/or flip the image if required by its orientation
CGContextConcatCTM(bitmap, transform);
// Set the quality level to use when rescaling
CGContextSetInterpolationQuality(bitmap, quality);
// Draw into the context; this scales the image
CGContextDrawImage(bitmap, transpose ? transposedRect : newRect, imageRef);
// Get the resized image from the context and a UIImage
CGImageRef newImageRef = CGBitmapContextCreateImage(bitmap);
UIImage *newImage = [UIImage imageWithCGImage:newImageRef];
// Clean up
CGContextRelease(bitmap);
CGImageRelease(newImageRef);
return newImage;
}
并将您的UIImage调整为非视网膜的UIImage视图大小,并将视网膜的视图大小乘以2。
使用视网膜 (x2( 图像时,您正在加载的图像占用的内存约为 4 倍,而 (x3( 图像占用的内存约为 (x3( 的 9 倍。使用 png 等格式时的数据需要解压缩、复制并发送到 GPU,在某些情况下,这会导致每个图像的内存中有 3 个图像数据副本,这显然是不好的。您的iPad仍然应该有足够的内存来加载更多纹理,然后您可以实时绘制。
从您告诉我们的内容来看,很难知道您的问题真正在哪里,但您应该确保的第一件事是加载图像时,您应该序列化操作。这意味着您应该加载 1 个纹理,确保所有图像数据都已从加载中清除(3 个副本中的 2 个(,然后开始加载下一个纹理。我不知道你用什么来加载纹理,但老式的"获取原始RGBA数据"应该在你的情况下是最好的。
如果不是这种情况,并且您实际上加载了太多纹理,那么您需要考虑如何最小化纹理数量或其分辨率,您达到了设备功能,并且您无能为力。使用纹理图集可能会对您有很大帮助。
在纹理加载和删除方面,您可以考虑重用纹理,向其发送新数据,而不是删除和创建新纹理。对于图像数据本身,您可以在一些加载时间内加载图像(甚至可能是第一次运行应用程序(,然后将原始RGBA数据保存到新文件中。使用这种方法将显着减少纹理加载时间和内存占用,缺点是您将使用用户磁盘空间。