此文,將嘗試動態從某個不肯定的文件夾中加載資源文件.文章,會繼續完善自定義的 imageNamed 函數,併爲下一篇文章鋪墊.ios
正如咱們常常所說的那樣,大多數情景知道作事的意義每每比作事的方法自己更有意義.意義自己,每每蘊含着目的,最終的需求一類的東西;而方法,只是咱們暫時尋找的用來達到最終的目的採起的一種可行的手段.知曉意義自己的意義在於,在之後的之後,咱們有可能找到更合適的方法來實現目的;也就是咱們所說的,到知識的豐富性獲得必定程度以後,許多人在本身的我的技能提高過程當中,多少總會有那種融會貫通,一通百通的狀況出現.能夠確定的是,那種醍醐灌頂的感受,確定不是單純的編碼行數的變化的引發的;更多的,是因爲你在有意無心中關於某個編碼需求自己的意義的探尋所促成的.git
具體到這裏,咱們爲何須要動態的資源文件夾呢?就目前的探討自己所透露出來的信息而言,主要是由於咱們的main.bundle放在了app裏,而iOS App自己的打包進去的文件,在用戶手機上是隻讀的.這樣表述,有三層含義:github
從特定的緩存目錄讀取加載資源文件,能夠看作動態資源文件夾的一種特殊形式,因此咱們先試着處理這種單一的狀況.緩存
在iOS App中, 固定 的緩存目錄和 特定 的緩存目錄,仍是有區別的.主要是由於真機上iOS App每次啓動時,其對應的文件目錄是動態變化的.也就是說,咱們之後若是有存儲文件路徑的需求,必定要記住只能存儲文件相對於程序沙盒主目錄 NSHomeDirectory 的相對路徑.順便說一句,主目錄的程序主目錄的可見子目錄有3個,分別是: Documents , Library , tmp ,具體介紹,可參考博文: iOS沙盒文件讀寫app
- Documents:蘋果建議將程序建立產生的文件以及應用瀏覽產生的文件數據保存在該目錄下,iTunes備份和恢復的時候會包括此目錄
如今咱們的資源目錄,將假定固定放在相對目錄 Library/Caches/patch 中,其名爲 main.bundle函數
那麼在須要時,咱們就能夠這樣訪問到咱們的資源文件夾:編碼
NSArray * LibraryPaths = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES); NSString * cacheBundleDir = [[LibraryPaths objectAtIndex:0] stringByAppendingFormat:@"/Caches/Patch/"]; NSLog(@"緩存資源目錄: %@", cacheBundleDir); // 模擬器示例輸出: 緩存資源目錄: /Users/yanfeng/Library/Developer/CoreSimulator/Devices/930159D0-850F-43CE-88D2-08BE9D4A7E7F/data/Containers/Data/Application/EE3A92AB-2DBE-44C5-9103-11BAC7AECE15/Library/Caches/Patch/
NSString * bundleName = @"main.bundle"; NSError * err = nil; NSFileManager * defaultManager = [NSFileManager defaultManager]; if ( ! [defaultManager fileExistsAtPath:cacheBundleDir]) { [defaultManager createDirectoryAtPath:cacheBundleDir withIntermediateDirectories:YES attributes:nil error: &err]; if(err){ NSLog(@"初始化目錄出錯:%@", err); } NSString * defaultBundlePath = [[NSBundle mainBundle].resourcePath stringByAppendingPathComponent: bundleName]; NSString * cacheBundlePath = [cacheBundleDir stringByAppendingPathComponent:bundleName]; [defaultManager copyItemAtPath: defaultBundlePath toPath:cacheBundlePath error: &err]; if(err){ NSLog(@"複製初始資源文件出錯:%@", err); } }
代碼,基本就像上面那樣,有幾個點我想着重說一下:.net
由於目錄是特定的,咱們只要每次App啓動後,根據相對路徑動態獲取絕對路徑,進而拿到 緩存目錄中 main.bundle 資源包路徑,而後就可使用已有的方法,從 bundle 裏取圖片便可:code
NSArray * LibraryPaths = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES); NSString * cacheBundleDir = [[LibraryPaths objectAtIndex:0] stringByAppendingFormat:@"/Caches/Patch/"]; NSString * bundleName = @"main.bundle"; NSString * imgName = @"sample@3x"; NSString * bundlePath = [cacheBundleDir stringByAppendingPathComponent: bundleName]; NSBundle * cacheMainBundle = [NSBundle bundleWithPath:bundlePath]; NSString * imgPath = [cacheMainBundle pathForResource:imgName ofType:@"png"]; UIImage * image = [UIImage imageWithContentsOfFile: imgPath]; self.sampleImageView.image = image;
這裏,主要是和實現iOS圖片等資源文件的熱更新化(二):自定義的動態 imageNamed的類目方法結合擴展下,使原來的類目擴展支持從動態的緩存目錄讀取bundle,思路自己也很簡單,只要更改下用於肯定bundle位置處的代碼便可:orm
+ (UIImage *)imageNamed:(NSString *)imgName bundle:(NSString *)bundleName cacheDir:(NSString *)cacheDir { NSArray * LibraryPaths = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES); NSString * cacheBundleDir = [NSBundle mainBundle].resourcePath; if (cacheDir) { cacheBundleDir = [[[LibraryPaths objectAtIndex:0] stringByAppendingFormat:@"/Caches"] stringByAppendingPathComponent:cacheDir]; } bundleName = [NSString stringWithFormat:@"%@.bundle",bundleName]; imgName = [NSString stringWithFormat:@"%@@3x",imgName]; NSString * bundlePath = [cacheBundleDir stringByAppendingPathComponent: bundleName]; NSBundle * mainBundle = [NSBundle bundleWithPath:bundlePath]; NSString * imgPath = [mainBundle pathForResource:imgName ofType:@"png"]; UIImage * image; static NSString * model; if (!model) { model = [[UIDevice currentDevice]model]; } if ([model isEqualToString:@"iPad"]) { NSData * imageData = [NSData dataWithContentsOfFile: imgPath]; image = [UIImage imageWithData:imageData scale:2.0]; }else{ image = [UIImage imageWithContentsOfFile: imgPath]; } return image; }
原來的從 ipa 包中加載 資源文件的邏輯能夠基於此方法重寫:
+ (UIImage *)imageNamed:(NSString *)imgName bundle:(NSString *)bundleName { return [self imageNamed:imgName bundle:bundleName cacheDir:nil]; }
*+ (UIImage *)imageNamed:(NSString *)imgName bundle:(NSString *)bundleName cacheDir:(NSString )cacheDir 方法中的 cacheDir 也是支持多級目錄的,如:
UIImage * image = [UIImage imageNamed:@"sub/sample" bundle:@"main" cacheDir:@"patch/default"]; self.sampleImageView.image = image;
注意,此時初始複製到緩存目錄的邏輯,也是適當對應子目錄變動下:
NSArray * LibraryPaths = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES); NSString * cacheBundleDir = [[LibraryPaths objectAtIndex:0] stringByAppendingFormat:@"/Caches/Patch/default/"]; NSLog(@"緩存資源目錄: %@", cacheBundleDir);