您正在自动imageWithData
释放池中创建一个自动释放对象 ( ),然后返回该对象,然后立即耗尽您的池。最简单的解决方法是删除该自动释放池。为什么有那个游泳池?只是为了立即排水NSData
?但是您根本不需要它NSData
,因为您可以直接检索图像:
@implementation Helpers
+ (UIImage *) getThumbnailImageIfExists:(NSString *)ItemSKU withManufacturer: (NSNumber *) aManufacturerID {
NSString *fileName = [[[SharedFunctions sharedInstance] getLargeFileName:[aManufacturerID stringValue] withPhotoName:ItemSKU] stringByReplacingOccurrencesOfString:@"_lg.jpg" withString:@"_tn.jpg"];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsPath = [paths objectAtIndex:0];
NSString *savePath = [documentsPath stringByAppendingPathComponent:[fileName lowercaseString]];
return [UIImage imageWithContentsOfFile:savePath];
}
@end
如果您真的想确保不将各种字符串和数组变量(即 、和fileName
)paths
放入调用者的自动释放池中,则可以解决该问题,但我不确定这有多重要(至少与将被放入池中的相比)。documentsPath
savePath
NSData
考虑这个替代实现:
+ (UIImage *)getThumbnailImageIfExists:(NSString *)itemSKU withManufacturer:(NSNumber *)aManufacturerID
{
UIImage *image;
static NSString *documentsPath;
static NSCache *cache;
// create docsPath and cache once and only once
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
NSArray *searchPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
documentsPath = searchPaths[0];
cache = [[NSCache alloc] init];
cache.countLimit = 100;
});
// now do your image retrieval
@autoreleasepool {
NSString *fileName = [[[SharedFunctions sharedInstance] getLargeFileName:[aManufacturerID stringValue] withPhotoName:itemSKU] stringByReplacingOccurrencesOfString:@"_lg.jpg" withString:@"_tn.jpg"];
NSString *savePath = [documentsPath stringByAppendingPathComponent:[fileName lowercaseString]];
image = [cache objectForKey:savePath];
if (!image)
{
image = [[UIImage alloc] initWithContentsOfFile:savePath]; // note, not an autoreleased object
[cache setObject:image forKey:savePath];
}
}
return image;
}
我在这里做几件事:
像以前一样,我已经删除了不必要的NSData
逻辑。无需将文件加载到 a中NSData
然后UIImage
从中创建 a ,然后丢弃NSData
.
NSCache
如果您为同一个 SKU/制造商重复调用此图像,则通过存储它加载的图像将节省大量内存(以及性能改进) 。如果您碰巧多次请求相同的图像,它可以防止您创建重复的图像。使用NSCache
解决了这个问题。通过我键入NSCache
图像的文件名,这是一个方便使用的键(尽管您也可以使用一些由制造商代码和 SKU 组成的字符串;这取决于您)。
我利用自己dispatch_once
设置了两个静态变量:
坦率地说,我倾向于移动documentsPath
和/或cache
作为一些单例实例的实例变量,并在适当的init
方法中设置这些变量而不是使用dispatch_once
,但我试图通过修改来向您展示如何做到这一点您与我们分享的方法。
真的很小的变化,但我总是使用 camelCase(以小写字母开头)作为变量名,所以我ItemSKU
改为itemSKU
.
虽然我已经使用了您的@autoreleasepool
块,但通常不需要这样做,除非您在单个循环中多次调用此方法for
,例如。如果这些是在表格视图或集合视图中使用的缩略图,@autoreleasepool
则不需要该块。但是我把它保留在那里,以防这些非常特殊的情况之一适用。
就个人而言,我@autoreleasepool
在自包含代码块周围使用块,而不是返回某些值的代码。但是,如果您的情况需要,您可以执行上述操作。
cache
如果您对同一图像多次调用此方法,则使用将产生巨大的影响(在内存消耗和性能方面)。static
和dispatch_once
for的使用对documentsPath
性能有适度的影响,但如果你经常调用它,那么它就会变得引人注目并且你可能需要考虑改进。
如果您看到内存增加,则使用@autoreleasepool
块很有用,但稍后会在完成后回落到合理的水平,但您只是想减少那个“高水位线”。如果问题是内存永远不会下降,那么自动释放池将无济于事;问题出在其他地方。
您应该自己尝试一下,通过分析器运行它,并检查性能和内存使用情况。就个人而言,我通常会专注于缓存的使用,而不是那么担心,@autoreleasepool
除非您调用此方法的方式有什么特殊之处(例如,您在一个循环中调用了数千次for
),但它是需要考虑的事情。对于大多数场景,真正的好处将来自缓存的使用,而不是@autorelease
块。