我有以下功能可以打开图像,缩放图像并将其保存到另一个文件中。
-(void)writeFileToIcon:(NSString *)fullPath :(NSString *)finalPath :(NSSize)outputSize
{
NSData *dataToWrite;
NSBitmapImageRep *rep;
rep = [NSBitmapImageRep imageRepWithData:[[self scaleImage:[[NSImage alloc]initWithContentsOfFile:fullPath] toSize:outputSize] TIFFRepresentation]];
dataToWrite = [rep representationUsingType:NSPNGFileType properties:nil];
[dataToWrite writeToFile:finalPath atomically:YES];
}
- (NSImage *)scaleImage:(NSImage *)image toSize:(NSSize)targetSize
{
if ([image isValid])
{
NSSize imageSize = [image size];
float width = imageSize.width;
float height = imageSize.height;
float targetWidth = targetSize.width;
float targetHeight = targetSize.height;
float scaleFactor = 0.0;
float scaledWidth = targetWidth;
float scaledHeight = targetHeight;
NSPoint thumbnailPoint = NSZeroPoint;
if (!NSEqualSizes(imageSize, targetSize))
{
float widthFactor = targetWidth / width;
float heightFactor = targetHeight / height;
if (widthFactor < heightFactor)
{
scaleFactor = widthFactor;
}
else
{
scaleFactor = heightFactor;
}
scaledWidth = width * scaleFactor;
scaledHeight = height * scaleFactor;
if (widthFactor < heightFactor)
{
thumbnailPoint.y = (targetHeight - scaledHeight) * 0.5;
}
else if (widthFactor > heightFactor)
{
thumbnailPoint.x = (targetWidth - scaledWidth) * 0.5;
}
NSImage *newImage = [[NSImage alloc] initWithSize:NSMakeSize(scaledWidth, scaledHeight)];
[newImage lockFocus];
NSRect thumbnailRect;
thumbnailRect.origin = NSZeroPoint;
thumbnailRect.size.width = scaledWidth;
thumbnailRect.size.height = scaledHeight;
[image drawInRect:thumbnailRect
fromRect:NSZeroRect
operation:NSCompositeSourceOver
fraction:1.0];
[newImage unlockFocus];
return newImage;
}
return nil;
}
return nil;
}
但是每次调用此函数时,内存使用率都会越来越高(1000次调用最多可达5 GB)
问题是drawRect函数,它似乎需要大量内存(根据分析器),但不会释放它。
我如何“要求”ARC释放它?
感谢。
答案 0 :(得分:2)
可能需要查看整个代码才能找到问题。不过有一个想法是:在ARC下,你不能打电话给#34;发布&#34;在对象上,但如果将对象的指针设置为&#34; nil&#34;,则将释放该对象(除非在某处存在对该对象的其他强引用)。
我建议您跟踪您的代码并确保您不再拥有您不再需要的对象。如果您的代码封装和结构良好,那么这不应该发生。
但是,如果你的代码设计得很好,那么实际需要这么多的内存(不太可能,但不知道没有更多细节)。如果是这种情况,那么让系统管理内存,它将在适当时释放对象。如果内存使用是一个问题,请尝试在某处进行优化。
偏离主题:这些长嵌套的方法在方法中有多个返回点并不是一个好主意;我建议你稍微重新构建你的代码。如果您编写更清晰的代码,您将对其进行更多控制,并且您将更快地找到问题的解决方案。
答案 1 :(得分:1)
您是从循环调用此函数还是不返回主事件循环?添加明确的@autoreleasepool
可能有所帮助。
-(void)writeFileToIcon:(NSString *)fullPath :(NSString *)finalPath :(NSSize)outputSize
{
@autoreleasepool {
NSBitmapImageRep *rep = [NSBitmapImageRep imageRepWithData:[[self scaleImage:[[NSImage alloc]initWithContentsOfFile:fullPath] toSize:outputSize] TIFFRepresentation]];
NSData *dataToWrite = [rep representationUsingType:NSPNGFileType properties:nil];
[dataToWrite writeToFile:finalPath atomically:YES];
}
}
理论上,这并不是必需的,因为在某些情况下,使用ARC编译的代码会使自动释放池短路。但是,你可能会以某种方式击败这种优化。
请注意,在逻辑上内存分配成为问题的地方,通常最好这样做。因此,您调用此方法的for
循环将是@autoreleasepool
更好的地方。
答案 2 :(得分:1)
我的猜测是你的问题与图像类中的缓存有关,但这可能是错误的。什么似乎改善了问题:
-(void)writeFileToIcon:(NSString *)fullPath :(NSString *)finalPath :(NSSize)outputSize
{
// wrap in autorelease pool to localise any use of this by the image classes
@autoreleasepool
{
NSImage *dstImage = [self scaleImageFile:finalPath toSize:outputSize];
NSBitmapImageRep *rep = [[NSBitmapImageRep alloc] initWithData:[dstImage TIFFRepresentation]];
NSData *dataToWrite = [rep representationUsingType:NSPNGFileType properties:nil];
[dataToWrite writeToFile:finalPath atomically:YES];
}
}
- (NSImage *)scaleImageFile:(NSString *)fullPath toSize:(NSSize)targetSize
{
NSImageRep *srcImageRep = [NSImageRep imageRepWithContentsOfFile:fullPath];
if (srcImageRep == nil)
return nil;
NSSize imageSize = NSMakeSize(srcImageRep.pixelsWide, srcImageRep.pixelsHigh);
NSSize scaledSize;
NSPoint thumbnailPoint = NSZeroPoint;
NSRect thumbnailRect;
if (!NSEqualSizes(imageSize, targetSize))
{
// your existing scale calculation
...
scaledSize = NSMakeSize(scaledWidth, scaledHeight);
}
else
scaledSize = imageSize;
srcImageRep.size = scaledSize;
NSImage *newImage = [[NSImage alloc] initWithSize:scaledSize];
[newImage lockFocus];
thumbnailRect.origin = NSZeroPoint;
thumbnailRect.size = scaledSize;
[srcImageRep drawInRect:thumbnailRect];
[newImage unlockFocus];
return newImage;
}
这使用NSImageRep
,在这种情况下出现以减少内存占用。在使用缩放到32x32的全屏桌面图像的示例运行中,上面徘徊在16Mb左右,而原始NSImage
版本稳定地增长到32Mb。 YMMV当然。
HTH