ios – 使用Xcode资产目录的UIImage缓存

我们都知道UI Image的imageNamed:方法的神秘的幕后缓存机制.在苹果的 UIImage Class Reference中,它说:

In low-memory situations,image data may be purged from a UIImage object to free up memory on the system. This purging behavior affects only the image data stored internally by the UIImage object and not the object itself. When you attempt to draw an image whose data has been purged,the image object automatically reloads the data from its original file. This extra load step,however,may incur a small performance penalty.

事实上,图形数据不会“从UIImage对象中清除,以释放系统上的内存”,但是文档建议.相反,应用程序会收到内存警告,直到它由于内存压力而退出.
编辑:在Xcode项目中使用传统的图像文件引用时,UIImage缓存工作正常.只是转换到资产目录时,内存从未被释放.

我实现了一个UIScrollView与几个UIImageViews滚动浏览一长串图像.当滚动时,下一张图像正在加载并分配给UIImageView的图像属性,从而删除之前已保存的UIImage的强大链接.

由于imageNamed:的缓存机制,我很快就用尽了内存,而应用程序终止了分配大约170 MB的内存.

当然,有很多有趣的解决方案来实现自定义缓存机制,包括覆盖类别中的imageNamed:class方法.通常,使用类方法imageWithContentOfFile:不缓存图像数据,因为即使是由苹果开发商在WWDC 2011提出的建议.

这些解决方案适用于常规的图像文件,尽管您必须获取不像我想要的那样优雅的路径和文件扩展名.

尽管如此,我正在使用Xcode 5中引入的新资产目录,以利用有条件地加载图像的机制,具体取决于设备和高效的图像文件存储.到目前为止,似乎没有直接的方式从资产目录加载图像而不使用imageNamed:,除非我缺少一个明显的解决方案.

你们已经找出了一个UIImage缓存机制与资产目录?

我想在UIImage上实现类似于以下的类别:

static NSCache *_cache = nil;

@implementation UIImage (Caching)

+ (UIImage *)cachedImageNamed:(Nsstring *)name {
    if (!_cache) _cache = [[NSCache alloc] init];

    if (![_cache objectForKey:name]) {
        UIImage *image = ???; // load image from Asset Catalog without internal caching mechanism
        [_cache setobject:image forKey:name];
    }

    return [_cache objectForKey:name];
}

+ (void)emptyCache {
    [_cache removeAllObjects];
}

@end

当然,使用资产目录可以更好地控制UIImage的内部高速缓存以及在低内存条件下清除图像数据的可能性.

感谢您的阅读,期待您的意见!

解决方法

更新:缓存驱逐工作罚款(至少自iOS 8.3以来).

我正在遇到同样的问题(iOS 7.1.1),虽然@Lukas可能是正确的

There is a high probability that the mistake is not inside Apple’s … caching but in your .. code.

所以我写了一个非常简单的测试应用程序(查看下面的完整的源),我仍然看到这个问题.如果你看到有什么问题,请让我知道.我知道它确实取决于图像大小.我只看到iPad Retina的问题.

@interface ViewController ()

  @property (nonatomic,strong) UIImageView *imageView;
  @property (nonatomic,strong) NSArray *imageArray;
  @property (nonatomic) NSUInteger   counter;

  @end

  @implementation ViewController

  - (void)viewDidLoad
  {
      [super viewDidLoad];

      self.imageArray = @[@"img1",...,@"img568"];
      self.counter = 0;

      UIImage *image = [UIImage imageNamed:[self.imageArray objectAtIndex:self.counter]];
      self.imageView = [[UIImageView alloc] initWithImage: image];
      [self.view addSubview: self.imageView];

      [self performSelector:@selector(loadNextimage) withObject:nil afterDelay:1];
  }

  - (void)didReceiveMemoryWarning
  {
      [super didReceiveMemoryWarning];
      NSLog(@"WARN: %s",__PRETTY_FUNCTION__);
  }


  - (void)loadNextimage{

      self.counter++;
      if (self.counter < [self.imageArray count])
      {
          NSLog(@"INFO: %s - %lu - %@",__PRETTY_FUNCTION__,(unsigned long)self.counter,[self.imageArray objectAtIndex:self.counter]);
          UIImage *image = [UIImage imageNamed:[self.imageArray objectAtIndex:self.counter]];
          self.imageView.frame = CGRectMake(0,image.size.width,image.size.height);
          [self.imageView setimage:image];

          [self performSelector:@selector(loadNextimage) withObject:nil afterDelay:0.2];
      } else
      {
          NSLog(@"INFO: %s %@",@"finished");
          [self.imageView removeFromSuperview];
      }
  }
  @end

在线实施

我写了一些代码来保持图像资源,但是加载了imageWithData或imageWithContentsOfFile:use xcassets without imageNamed to prevent memory problems?

相关文章

UITabBarController 是 iOS 中用于管理和显示选项卡界面的一...
UITableView的重用机制避免了频繁创建和销毁单元格的开销,使...
Objective-C中,类的实例变量(instance variables)和属性(...
从内存管理的角度来看,block可以作为方法的传入参数是因为b...
WKWebView 是 iOS 开发中用于显示网页内容的组件,它是在 iO...
OC中常用的多线程编程技术: 1. NSThread NSThread是Objecti...