使用Xcode Asset Catalogs进行UIImage缓存 [英] UIImage caching with Xcode Asset Catalogs

查看:174
本文介绍了使用Xcode Asset Catalogs进行UIImage缓存的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我们都知道UIImage的 imageNamed:方法的神秘的幕后缓存机制。在Apple的 UIImage类参考中,它说:

We all know about the mysterious behind-the-scenes caching mechanism of UIImage's imageNamed: method. In Apple's UIImage Class Reference it says:


在内存不足的情况下,可能会从UIImage对象中清除图像数据以释放系统上的内存。此清除行为仅影响由UIImage对象内部存储的图像数据,而不影响对象本身。当您尝试绘制其数据已清除的图像时,图像对象会自动从其原始文件中重新加载数据。

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缓存工作正常。

In fact, image data will not be "purged from a UIImage object to free up memory on the system" as the documentation suggests, however. Instead, the app receives memory warnings until it quits "due to memory pressure".
When using the conventional image file references in your Xcode project, the UIImage caching works fine. It's just when you transition to Asset Catalogs that the memory is never released.

我实现了一个UIScrollView和一些UIImageViews来滚动一个长的列表的图像。滚动时,下一个图像正在加载并分配给UIImageView的 image 属性,删除之前持有的UIImage的强链接。

I implemented a UIScrollView with a couple of UIImageViews to scroll through a long list of images. When scrolling, the next images are being loaded and assigned to the UIImageView's image property, removing the strong link to the UIImage it has been holding previously.

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

Because of imageNamed:'s caching mechanism, I quickly run out of memory, though, and the app terminates with around 170 MB memory allocated.

当然,有很多有趣的解决方案来实现自定义缓存机制,包括覆盖 imageNamed:类方法在一个类别。通常,使用不缓存图像数据的类方法 imageWithContentOfFile:来替代,就像Apple开发商在WWDC 2011上所建议的那样。

Of course there are plenty of interesting solutions around to implement custom caching mechanisms, including overriding the imageNamed: class method in a category. Often, the class method imageWithContentOfFile: that does not cache the image data is used instead, as even suggested by Apple developers at the WWDC 2011.

这些解决方案适用于正常的图像文件,虽然你必须得到的路径和文件扩展名不是那么优雅,我想它是。

These solutions work fine for regular image files, although you have to get the path and file extension which is not quite as elegant as I would like it to be.

我使用了在Xcode 5中引入的新资产目录,以利用根据设备和高效的图像文件存储有条件地加载图像的机制。到现在为止,似乎没有直接的方法从资产目录加载图像,而不使用 imageNamed:,除非我缺少一个明显的解决方案。

I am using the new Asset Catalogs introduced in Xcode 5, though, to make use of the mechanisms of conditionally loading images depending on the device and the efficient image file storage. As of now, there seems to be no straight forward way to load an image from an Asset Catalog without using imageNamed:, unless I am missing an obvious solution.

你们有没有想出一个带有资产目录的UIImage缓存机制?

以实现类似于以下的UIImage类别:

I would like to implement a category on UIImage similar to the following:

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 的内部缓存,以及在使用资产目录时,如文档中所述在低内存条件下清除图像数据的可能性。

Even better would of course be a way to have more control over UIImage's internal cache and the possibility to purge image data on low memory conditions as described in the documentation when using Asset Catalogs.

感谢您阅读,期待您的想法!

Thank you for reading and I look forward to your ideas!

推荐答案

UPDATE:缓存驱逐工作的罚款(至少从iOS 8.3)。

UPDATE: Cache eviction works fines (at least since iOS 8.3).

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

I am running into the same issue (iOS 7.1.1) and I kind of though that @Lukas might be right


很有可能的错误不是在苹果的...缓存,而是在你的。 。代码。

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

因此,我写了一个非常简单的测试应用程序如果您发现任何错误,请告诉我们。我知道这确实取决于图像大小。我只能在iPad Retina上看到这个问题。

Therefore I have written a very simple Test App (view full source below) where I still see the issue. If you see anything wrong with it, please let the me know about it. I know that it really depends on the image sizes. I only see the issue on an 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, 0, image.size.width, image.size.height);
          [self.imageView setImage:image];

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






Inplace实现



我写了一些代码来保存图片资源,但是加载它 imageWithData: imageWithContentsOfFile 使用没有imageNamed的xcassets以防止内存问题?

这篇关于使用Xcode Asset Catalogs进行UIImage缓存的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆