簡體   English   中英

使用Xcode資產目錄進行UIImage緩存

[英]UIImage caching with Xcode Asset Catalogs

我們都知道UIImage的imageNamed:方法的神秘的幕后緩存機制。 在Apple的UIImage類參考中,它說:

在內存不足的情況下,可以從UIImage對象中清除圖像數據以釋放系統上的內存。 此清除行為僅影響UIImage對象內部存儲的圖像數據,而不影響對象本身。 當您嘗試繪制其數據已被清除的圖像時,圖像對象會自動從其原始文件重新加載數據。 然而,這個額外的負載步驟可能會導致很小的性能損失。

實際上,正如文檔所示,圖像數據不會“從UIImage對象中清除以釋放系統上的內存”。 相反,應用程序會收到內存警告,直到它“因內存壓力”退出。
編輯:在Xcode項目中使用傳統的圖像文件引用時,UIImage緩存工作正常。 只是當您轉換到資產目錄時,內存永遠不會被釋放。

我實現了一個帶有幾個UIImageViews的UIScrollView來滾動瀏覽一長串圖像。 滾動時,正在加載下一個圖像並將其分配給UIImageView的image屬性,刪除之前保存的UIImage的強鏈接。

由於imageNamed:的緩存機制,我很快就會耗盡內存,應用終止時分配了大約170 MB的內存。

當然,有很多有趣的解決方案可以實現自定義緩存機制,包括覆蓋類別中的imageNamed: class方法。 通常,使用不緩存圖像數據的類方法imageWithContentOfFile:正如Apple開發人員在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可能是對的

這個錯誤很可能不在Apple的......緩存中,而是在你的..代碼中。

因此,我寫了一個非常簡單的測試應用程序(查看下面的完整源代碼),我仍然看到了這個問題。 如果您發現任何問題 ,請讓我知道。 我知道這取決於圖像尺寸。 我只在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

就地實施

我寫了一些代碼來保存圖像資產,但用imageWithData:imageWithContentsOfFile加載它: 使用沒有imageNamed的xcassets來防止內存問題?

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM