在組件化前期的工作中顷级,我們會面臨如何管理圖片柜裸、音視頻等資源的問題。我們需要關(guān)注的問題是如何將相應(yīng)的資源和組件一起打包本鸣,并保證能夠在組件內(nèi)和組件間的正常使用。以下內(nèi)容均針對于使用CocoaPods
方式組件化對資源文件管理的討論硅蹦。
文件管理方式:
1. 集中式管理
將所有的資源文件做成一個組件荣德,其它相應(yīng)的組件依賴該資源組件,通過組件暴露的相關(guān)接口獲取對應(yīng)的資源童芹。
2. 分散式管理
將資源文件進(jìn)行清晰分類涮瞻,對應(yīng)的資源文件嵌入至對應(yīng)的組件中,如有共用文件假褪,抽取公共資源組件將公共資源放入該組件中署咽,或者將公共資源直接放至主工程中。
集中式管理與分散式管理優(yōu)缺點(diǎn)對比:
總結(jié)建議:
集中式管理可方便維護(hù)生音,可對項(xiàng)目文件進(jìn)行統(tǒng)一管理艇抠,此外還可降低文件冗余的概率,可用于較大久锥、耦合嚴(yán)重的項(xiàng)目家淤。倘若是新項(xiàng)目或者組件對主工程依賴性不強(qiáng)的組件,可采用分散式管理瑟由,將組件的相關(guān)資源與組件綁定絮重。
resources和resource_bundles
resoures
和resource_bundles
是CocoaPods
兩種資源文件引用的方式。
1. resource/resources
resource
與resources
兩個屬性功能相同歹苦,不同的是resources
可以批量指定文件資源青伤,resource
只能指定單個文件資源。
1.1 語法
spec.resource = 'Resources/HockeySDK.bundle'
spec.resources = ['Images/*.png', 'Sounds/*']
1.2 官方描述 Podspec語法官方介紹
resources
將指定的資源復(fù)制到目標(biāo)bundle
殴瘦,我們強(qiáng)烈建議開發(fā)者使用 resource bundles
去構(gòu)建靜態(tài)資源庫狠角。使用resources
屬性僅僅是將指定的文件資源復(fù)制到目標(biāo)bundle
,如此Xcode
不會對相關(guān)資源進(jìn)行優(yōu)化操作蚪腋。
看完官方描述丰歌,我們第一直覺就會放棄使用這種方式了。雖然如此屉凯,但是我們還是去看看如果使用這種方式具體會產(chǎn)生哪些影響立帖。
1.3 resource
探究
使用pod lib create SCResource_Resources
命令創(chuàng)建項(xiàng)目。打開Example
中的項(xiàng)目悠砚,并刪除SCResource_Resources.podspec
中無用的代碼晓勇。如下圖所示。
1.3.1 resource
不嵌入xcassets
文件
選中ReplaceMe.m
文件,右鍵Show in Finder
,調(diào)至上一級文件夾绑咱,看到Classes
和Assets
文件夾绰筛。我們把ReplaceMe.m
刪除,并刪除SCResource_Resources.podspec
中的s.source_files
,因?yàn)槲覀冊谫Y源組件中暫時不用編輯代碼描融。然后把事先準(zhǔn)備好的圖片資源放入Assets
文件夾下,并設(shè)置resource
屬性别智。最終如下圖所示。
終端pod install
后稼稿,便可以看到圖片資源已經(jīng)被加到Resources
文件夾下薄榛。
查看資源文件在包中的位置
真機(jī)運(yùn)行,選擇Products
文件夾下的SCResource_Resources_Example.app
右鍵Show in Finder
,選中SCResource_Resources_Example
右鍵让歼,選擇顯示包內(nèi)容
敞恋,就可以看到我們添加的Images
文件夾。查看并記錄文件夾的大小谋右。發(fā)現(xiàn)和事先我們準(zhǔn)備的文件夾大小相同,均為21.5M硬猫。
資源文件獲取
一般情況下,我們在項(xiàng)目中獲取圖片都是通過使用imageNamed:
方法去獲取改执。那么現(xiàn)在我們把圖片資源放在組件中啸蜜,通過這樣的方式也能夠獲取嗎?
我們在Example
項(xiàng)目中的SCViewController.m
的viewDidLoad
方法中鍵入如下代碼:
前面我們查看過
Images
最終在APP中的路徑辈挂,并且容易找到goodluck_smile
圖片的路徑是Images/好運(yùn)墻/goodluck_smile
衬横。運(yùn)行項(xiàng)目,發(fā)現(xiàn)我們拿到的image
對象是nil
终蒂。很糟糕蜂林,我們沒有獲取到對應(yīng)的圖片。查看注釋可以知道
imageNamed:
是從main bundle
中獲取文件資源拇泣,那么如果我們把圖片放在主工程中的Images.xcassets
文件中噪叙,這里的文件在最終的包中的路徑是什么呢?帶著這樣的疑問霉翔,我們簡單地把一張圖片(goodluck_smile
)放入Images.xcassets
中睁蕾,真機(jī)運(yùn)行后,通過上述查看資源文件在包中的位置
的操作方法進(jìn)行查看债朵。可以看到多出了
Assets.car
文件子眶,由此可以知道,Images.xcassets
中的圖片資源葱弟,最終會被打包成Assets.car
文件壹店,也從側(cè)面可以說明Assets.car
文件所在的目錄就是main bundle
的路徑,那么為什么組件中的圖片沒有被正常獲取呢芝加?難道是因?yàn)槲覀兟窂絾栴}?前面我們已經(jīng)說過
goodluck_smile
圖片是在Images/好運(yùn)墻/
下,那么我么手動拼接試試藏杖。為了排除其它影響将塑,我們刪除掉前面在Images.xcassets
中的圖片文件,并運(yùn)行蝌麸。
這時候点寥,我們正確獲取到了我們想要的圖片。現(xiàn)在我們可以通過代碼來獲取到組件中的圖片了来吩,需要注意的點(diǎn)是需要傳入圖片的相對路徑敢辩,那么在xib
中又如何呢?
我們再Main.storyboard
中添加一個UIImageView
,并直接設(shè)置goodluck_smile
圖片,瞬間就心情大好弟疆,因?yàn)榱ⅠR就看到Main.storyboard
顯示了對應(yīng)的圖片戚长。
真機(jī)運(yùn)行,看看會不會有什么問題怠苔。
運(yùn)行后發(fā)現(xiàn)同廉,我們設(shè)置的圖片沒有正常顯示,那么也是因?yàn)槲覀円顚懴鄬β窂降脑騿岣趟荆课覀內(nèi)ピ囋嚒?/p>
這時候迫肖,發(fā)現(xiàn)Main.storyboard
沒有正常顯示圖片,但是真機(jī)運(yùn)行后攒驰,圖片顯示正常蟆湖。
總結(jié):
使用resource/resources
直接存放文件資源時,無論是通過代碼獲取圖片玻粪,還是在xib
中設(shè)置圖片帐姻,都需要填寫完整的相對路徑。當(dāng)然如果你想直接通過設(shè)置圖片名稱的方式獲取圖片奶段,那么你必須將圖片直接暴露在resources
文件下饥瓷,不能新建文件對相關(guān)資源做整理。
1.3.2 resource
嵌入xcassets
文件
在沒有組件化時痹籍,我們一般把圖片資源都放在Images.xcassets
文件內(nèi)管理呢铆,其為我們提供了許多優(yōu)化點(diǎn)和一些方便的功能,所以我們可能也希望在組件中也利用這些優(yōu)化和功能蹲缠。那么在resource
中如何通過xcassets
來管理圖片呢棺克?其實(shí)很簡單,只需在組件的Assets
文件夾下創(chuàng)建Asset Catalog
文件线定,再將圖片資源拖入即可娜谊。
這里需要注意的是:在創(chuàng)建Asset Catalog
文件后,其目錄可能不在組件的Assets
文件下斤讥,需要手動將其拖入至文件下纱皆。
pod install
后,對項(xiàng)目進(jìn)行編譯,如果出現(xiàn)如下錯誤派草,則選擇File -> Workspace Settings -> Build System
的New Build System(Default)
改為Legacy Build System
即可搀缠。
使用上文提到的查看資源文件在包中的位置
的方式查看文件資源,前面我們也提及到近迁,xcassets
文件最后打包進(jìn)APP是會轉(zhuǎn)成Assets.car
文件的艺普,我們找到該文件,并查看該文件的大小鉴竭。
文件大小變成了69.1M歧譬,是原先21.5M的好幾倍,這會大大增大包的大小搏存。
資源文件獲取
在查看資源文件路徑后瑰步,我們發(fā)現(xiàn),其路徑和在主工程中的Images.xcassets
在包中的路徑相同祭埂,那么可以推測面氓,正常使用相關(guān)方法應(yīng)該可以獲取到資源文件。
同樣在ViewDidLoad
方法中鍵入一下代碼蛆橡,看能否正確獲取圖片資源舌界。斷點(diǎn)運(yùn)行后,發(fā)現(xiàn)可正常獲取泰演。
使用xib
方式也一樣呻拌,這里就不再截圖,大家可以自己嘗試睦焕。
總結(jié):
resource
嵌入xcassets
文件時藐握,資源文件會被copy
至main bundle
中,可以正常獲取資源文件垃喊,但是會造成APP大小變大猾普,因此不建議使用。
2. resource_bundle/resource_bundles
和resource/resources
類似本谜,resource_bundle/resource_bundles
功能相同初家,區(qū)別在與指定一個和多個。
2.1 語法
spec.ios.resource_bundle = { 'MapBox' => 'MapView/Map/Resources/*.png' }
spec.resource_bundles = {
'MapBox' => ['MapView/Map/Resources/*.png'],
'MapBoxOtherResources' => ['MapView/Map/OtherResources/*.png']
}
2.2 官方描述 Podspec語法官方介紹
重點(diǎn)翻譯:強(qiáng)烈建議使用該方式為Pod
構(gòu)建靜態(tài)庫,文件資源通過鍵值匹配資源乌助,bundle
的名稱應(yīng)該包含Pod
的名稱來降低名稱沖突的可能性溜在。
2.3 resource_bundle
探究
下面同樣通過是否嵌入xcassets
文件來分析這兩種情況的優(yōu)劣。
2.3.1 resource_bundle
不嵌入xcassets
文件
不嵌入xcassets
文件時他托,和resource
一樣掖肋,直接將文件資源拖入至Assets
文件夾下,具體參考上文resource不嵌入xcasset文件
中的內(nèi)容赏参。然后修改podspec
文件制定文件資源的方式志笼,如下圖所示沿盅。
pod install
,真機(jī)運(yùn)行籽腕,查看資源文件在包中的位置
,可以看到一個SCResource_Resources.bundle
的文件嗡呼。查看該文件的大小為21.1M纸俭,比原文件略小皇耗。
再選擇SCResource_Resources.bundle
右鍵顯示包內(nèi)容
,可看到我們放進(jìn)去的Images
圖片文件夾揍很。
資源文件獲取
前面在resource
的章節(jié)中郎楼,我們已經(jīng)知道需要通過拼接資源的相對路徑才能獲取相應(yīng)的資源,所以我們這里也嘗試看看會發(fā)生什么窒悔。
在ViewDidLoad
方法中鍵入下面代碼:
UIImage *image = [UIImage imageNamed:@"SCResource_Resources.bundle/Images/好運(yùn)墻/goodluck_smile"];
斷點(diǎn)查看是否能正常獲取圖片資源呜袁。
在xib
中同樣這樣拼接,真機(jī)運(yùn)行简珠,看能否正常顯示圖片阶界。
運(yùn)行后,我們可以如預(yù)期一樣獲取資源文件聋庵。
總結(jié):
resource_bundle
不嵌入xcasset
文件膘融,需拼接文件的相對路徑才能正確獲取圖片資源。
2.3.2 resource_bundle
嵌入xcassets
文件
嵌入xcassets
文件時祭玉,也和resource
一樣氧映,創(chuàng)建xcassets
文件,拖入文件資源脱货,并拖入至Assets
文件夾下岛都,具體參考上文resource嵌入xcasset文件
中的內(nèi)容。
pod install
并真機(jī)運(yùn)行,查看資源文件在包中的位置
,我們同樣可以看到SCResource_Resources.bundle
文件振峻,查看文件大小臼疫,可以看到只有16.8M,比前面所有情況都要小扣孟。
再選擇SCResource_Resources.bundle
右鍵顯示包內(nèi)容
烫堤,可看到我們放進(jìn)去的Assets.car
文件。與前文的情況一致哈打。
資源文件獲取
在resource
的章節(jié)中塔逃,如果嵌套xcassets
文件,我們可以直接通過圖片名稱來獲取文件資源料仗,那么這里是不是類似呢湾盗,我們來試試。
在viewDidLoad
方法中鍵入下面代碼:
UIImage *image = [UIImage imageNamed:@"goodluck_smile"];
運(yùn)行立轧,查看image
對象是否存在格粪。
很遺憾躏吊,結(jié)果為nil
。那么我們拼接路徑呢帐萎?同樣在viewDidLoad
方法中鍵入下面代碼:
UIImage *image = [UIImage imageNamed:@"SCResource_Resources.bundle/goodluck_smile"];
運(yùn)行比伏,查看image
對象是否存在。
同樣的結(jié)果疆导,還是nil
赁项。
使用這種方式,我們需要換一個方法去獲取指定資源澈段,我們需要調(diào)用UIImage
的imageNamed:inBundle: compatibleWithTraitCollection:
方法悠菜。指定bundle和圖片的名稱即可。
NSString *bundleName = @"SCResource_Resources";
NSString *imageBundlePath = [[NSBundle mainBundle] pathForResource:bundleName ofType:@"bundle"];
NSBundle *imageBundle = [NSBundle bundleWithPath:imageBundlePath];
UIImage *image = [UIImage imageNamed:@"goodluck_smile" inBundle:imageBundle compatibleWithTraitCollection:nil];
運(yùn)行败富,查看image
對象是否存在
運(yùn)行結(jié)果如預(yù)期悔醋,可獲取對應(yīng)文件資源。
在xib
中如何設(shè)置呢?可以添加分類暴露bundleName
和imageName
使用IBInspectable
修飾兽叮,調(diào)用imageNamed:inBundle: compatibleWithTraitCollection:
方法芬骄。
總結(jié):
resource_bundle
嵌入xcasset
文件,包文件大小相對于其它情況較小鹦聪,但獲取文件資源時账阻,需要封裝方法調(diào)用UIImage
的imageNamed:inBundle: compatibleWithTraitCollection:
方法。
總結(jié)
使用CocoaPods
方式組件化椎麦,對文件資源進(jìn)行管理宰僧,建議使用resource_bundle/resource_bundles
嵌入xcassets
文件的方式。這樣一來可以使用xcassets
的一些特性和優(yōu)化观挎,也能夠在一定程度上減小包的體積琴儿。