天天看點

imageNamed與imageWithContentsOfFile小結

imageNamed與imageWithContentsOfFile小結

pexels-photo-892769.jpeg

本文主要講imageNamed與imageWithContentsOfFile的差異,需要注意的點,與實戰中遇到的坑。

好久沒寫過部落格了,什麼工作太忙,加班太晚我就不說了,都怪自己太懶,時間都是擠出來的。看着各位大牛寫的文章,簡直過瘾,希望有一天自己也能寫出這麼高品質、幹貨密集的文章,先從簡單的做起吧。

從差異說起

從磁盤加載圖檔,UIImage主要提供了兩種方式:

+(UIImage *)imageNamed:(NSString *)name;

+(UIImage *)imageWithContentsOfFile:(NSString *)path;

關于這兩種方法的使用時機,蘋果官方文檔描述如下:

Use the imageNamed:inBundle:compatibleWithTraitCollection: method (or the imageNamed: method) to create an image from an image asset or image file located in your app’s main bundle (or some other known bundle). Because these methods cache the image data automatically, they are especially recommended for images that you use frequently.

Use the imageWithContentsOfFile: or initWithContentsOfFile: method to create an image object where the initial data is not in a bundle. These methods load the image data from disk each time, so you should not use them to load the same image repeatedly.

也就是說,

imageNamed:

第一次加載圖檔時會緩存圖檔到記憶體,适合使用頻繁的圖檔,

imageWithContentsOfFile:

不會把圖檔緩存到記憶體,每次調用都要重新從磁盤加載一次。

在實際使用中我們要根據業務來判斷調用具體的方法,來最優化記憶體與性能。舉個例子:

  1. 登陸背景圖,隻會在使用者登陸的時候使用,而且圖檔較大,就建議用

    imageWithContentsOfFile:

    加載;
  2. 底導航圖示,圖示較小,使用頻繁,就建議使用

    imageNamed:

imageNamed:

方法還有個限制,它是在main bundle裡找圖檔,如果圖檔放在

Images.xcassets

或者直接把圖檔方在工程裡,參數直接傳圖檔名可以找到。像我司的圖檔是放在單獨建立的bundle裡,如果要用

imageNamed:

加載的話檔案名前面就要加上bundle名,像這樣

a.bundle/b.png

螢幕适配問題

iOS的圖檔檔案需要提供3種尺寸的1x、2x、3x,根據不同的螢幕尺寸我們需要加載不同的圖檔,關于不同螢幕的圖檔加載,蘋果已經幫我們封裝好了,我們隻需要将3中尺寸的圖檔放到工程中,然後調用

imageNamed:

或者

imageWithContentsOfFile:

,它會自動根據螢幕尺寸來加載不同的圖檔。

關于

imageNamed:

,官方文檔中有這麼一段讨論:

This method looks in the system caches for an image object with the specified name and returns the variant of that image that is best suited for the main screen.

imageWithContentsOfFile:

還沒找到官方文檔的說明(如果各位知道,歡迎各位大牛在評論中提出),不過我測試過是可以的。

使用imageWithContentsOfFile的一個坑

在使用

imageWithContentsOfFile:

加載圖檔的時候遇到一個坑,先上代碼:

+ (UIImage *)imageWithName:(NSString *)name type:(NSString *)type inBundle:(NSString *)bundle {
    NSString *imageBundlePath = [[NSBundle mainBundle] pathForResource:bundle ofType:@"bundle"];
    NSBundle *imageBundle = [NSBundle bundleWithPath:imageBundlePath];
    NSString *imagePath = [imageBundle pathForResource:name ofType:type];
    UIImage *image = [UIImage imageWithContentsOfFile:imagePath];
    return image;
}
           

很簡單的一個函數,就是擷取bundle全路徑,然後再擷取到bundle裡圖檔的全路徑,然後調用

imageWithContentsOfFile:

加載圖檔。在使用的時候也很正常,但是有一天發現某張圖加載不出來了。檢查資源檔案,隻有2x的圖(又是一個偷懶的程式員。。。很不建議這麼玩,雖然隻有2x的圖,在所有螢幕都能顯示,但是會造成圖檔的壓縮與放大,每個細節都很重要!!!),如果加上1x的圖就可以加載出來了。

經過調試發現問題就出在

pathForResource:ofType

上,這個函數是精确比對調用者輸入的檔案名,不會自動識别檔案名後面的

@2x

。修改後的代碼:

+ (UIImage *)imageWithName:(NSString *)name type:(NSString *)type inBundle:(NSString *)bundle {
    NSString *imageBundlePath = [[NSBundle mainBundle] pathForResource:bundle ofType:@"bundle"];
    NSBundle *imageBundle = [NSBundle bundleWithPath:imageBundlePath];
    NSString *imageFullName = [name stringByAppendingPathExtension:type];
    NSString *imagePath = [[imageBundle resourcePath] stringByAppendingPathComponent:imageFullName];
    UIImage *image = [UIImage imageWithContentsOfFile:imagePath];
    return image;
}
           

繼續閱讀