尝试在字典中缓存 uiImages,似乎不会影响加载时间
我使用标准缓存方法来缓存从 Documents 目录加载的一些 UIImage。图像显示在 UITableView 中。它们相当大——图像本身高达 600x600,并以 240x180 的图像视图显示(在视网膜显示屏上,因此分辨率差异并不大)。
当新单元格即将出现在屏幕上时,实时加载图像会导致一些延迟。因此,我在处理图像的对象中实现了一个缓存方法:
- (UIImage *)imageWithStyle:(NSString *)styleName {
NSLog(@"looking for image %@", self.imageFileName);
/* if we have a cached image in dictionary, return it */
if (imageCache == nil) imageCache = [[NSMutableDictionary alloc] init];
UIImage *returnImage = [imageCache objectForKey:styleName];
if (returnImage != nil) {
NSLog(@"returning cached image");
return returnImage;
}
/* otherwise, look for image at path */
NSString *path = [self cacheFilePathWithStyle:styleName];
UIImage * originalImage = [[UIImage alloc] initWithContentsOfFile:path];
/* if image doesnt exist at path, start download and return nil */
if (originalImage == nil) {
NSLog(@"image not found. downloading.");
[self downloadImageFromS3];
return nil;
}
/* found image at path */
/* scale image for screen */
if ([[UIScreen mainScreen] respondsToSelector:@selector(scale)] && [[UIScreen mainScreen] scale] == 2){
returnImage = [UIImage imageWithCGImage:[[originalImage autorelease] CGImage] scale:2.0 orientation:UIImageOrientationUp];
NSLog(@"scaling image for retina");
} else {
returnImage = [originalImage autorelease];
NSLog(@"image scaled for standard resolution");
}
/* cache image in dictionary */
NSLog(@"caching image");
[imageCache setObject:returnImage forKey:styleName];
return returnImage;
}
在表格视图出现在屏幕上之前,我强制所有图像处理对象运行此缓存方法,以确保图像存在于字典中,以便在以下情况下检索:它们需要被展示。通过 NSLog,我可以看到事情正在按预期进行。
我现在获得了无延迟的性能,但前提是图像在屏幕上出现一次之后。因此,当我最初看到表格视图时,我向下滚动,NSLogs 告诉我正在从缓存中检索图像,但我仍然遇到相同的加载延迟。单元格在屏幕上出现一次后,就会毫无延迟地加载。
我在这里缺少什么吗?我还需要做更多的事情来实际缓存图像吗?加载它并将其放入字典中似乎并不能解决问题。
谢谢!
更新
我现在已经放弃了。有一些尝试通过在新的上下文中绘制图像来强制加载图像,但目前我还不熟悉核心图形编程。我尝试过人们分享的一些代码,但没有运气。
相反,我将在表视图滚动时显示图像的低分辨率版本,并在表视图停止滚动时加载高分辨率版本,如通过其委托方法宣布的那样。至少我知道这种方法适用于任意数量的图像。
I'm using a standard caching method to cache some UIImages loaded from the Documents directory. The images are being displayed in a UITableView. They're pretty large – the images themselves are up to 600x600 and are displayed in imageviews that are 240x180 (on a retina display, so the res discrepancy is not large).
Loading the images in realtime causes some lag when a new cell is about to come onscreen. So I've implemented a caching method in the object that handles the image:
- (UIImage *)imageWithStyle:(NSString *)styleName {
NSLog(@"looking for image %@", self.imageFileName);
/* if we have a cached image in dictionary, return it */
if (imageCache == nil) imageCache = [[NSMutableDictionary alloc] init];
UIImage *returnImage = [imageCache objectForKey:styleName];
if (returnImage != nil) {
NSLog(@"returning cached image");
return returnImage;
}
/* otherwise, look for image at path */
NSString *path = [self cacheFilePathWithStyle:styleName];
UIImage * originalImage = [[UIImage alloc] initWithContentsOfFile:path];
/* if image doesnt exist at path, start download and return nil */
if (originalImage == nil) {
NSLog(@"image not found. downloading.");
[self downloadImageFromS3];
return nil;
}
/* found image at path */
/* scale image for screen */
if ([[UIScreen mainScreen] respondsToSelector:@selector(scale)] && [[UIScreen mainScreen] scale] == 2){
returnImage = [UIImage imageWithCGImage:[[originalImage autorelease] CGImage] scale:2.0 orientation:UIImageOrientationUp];
NSLog(@"scaling image for retina");
} else {
returnImage = [originalImage autorelease];
NSLog(@"image scaled for standard resolution");
}
/* cache image in dictionary */
NSLog(@"caching image");
[imageCache setObject:returnImage forKey:styleName];
return returnImage;
}
Before the tableview appears on screen, I force all of the image handling objects to run this caching method to ensure that the images are present in the dictionary to be retrieved when they need to be displayed. By the NSLog's I can see that things are working as they should.
I'm getting lag-free performance now, but only after the image has appeared once on screen. So, when I initially see the tableview, I scroll down and the NSLogs tell me that the images are being retrieved from the cache, but still I get the same loading lag. After a cell has appeared on screen once, it thereafter loads up with no lag.
Is there something I'm missing here? Is there something more that I have to to to actually cache the image? Loading it and putting it in the dictionary doesn't seem to do the trick.
Thanks!
UPDATE
I've given up on this for now. There are some attempts out there to force the images to load by drawing them in a new context, but I'm not familiar with core graphics programming at this point. I've tried some code that folks have shared, but with no luck.
Instead, I'm going to display low-res versions of the images while the tableview is scrolling and load high-res versions when the tableview stops scrolling as announced through its delegate methods. At least I know this approach will work with any number of images.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
来自
-[UIImage initWithContentsOfFile:]
的文档:我的猜测是,通过将所有图像加载到内存中,您的应用程序会消耗太多内存,导致 UIImage 类释放可以稍后从文件中重新加载的图像数据。
From the documentation for
-[UIImage initWithContentsOfFile:]
:My guess is that, by loading all images into memory, your app consumes too much memory, causing the
UIImage
class to release the image data it can reload from files later.如果您使用
[UIImage imageNamed:]
,它将为您完成所有这些缓存业务。无需滚动自己的缓存,然后想知道它是否正常工作。使用该方法的优点和缺点。优点:如果您两次使用同一个图像文件,它实际上不会加载两次,从而节省内存。缺点:缓存对内存有很大的影响,无论你是否自己推出缓存,你都需要认真考虑是否要这样做。
If you use
[UIImage imageNamed:]
, it'll do all this caching business for you. No need to roll your own cache and then wonder if it's working.An upside and a downside to using that method. Upside: If you use the same image file twice, it won't actually load it twice, saving you that memory. Downside: Caching has a big memory impact, and you want to think pretty hard about doing it, whether you roll your own or not.