前言
Android中的資源引用 & "R"
在接觸iOS
開(kāi)發(fā)之前,我也曾搞過(guò)一段時(shí)間的Android
開(kāi)發(fā)姿染。在Android開(kāi)發(fā)中赋咽,其對(duì)于資源的引用非常方便,我們可以通過(guò)"R
機(jī)制"來(lái)對(duì)Android中的圖片(Drawable)菌湃、布局(Layout)、動(dòng)畫(huà)配置(Anim)遍略、國(guó)際化字符串(String)惧所、尺寸(Dimen)等等資源進(jìn)行非常方便快捷的引用骤坐。什么是R機(jī)制
?在我們創(chuàng)建一個(gè)Android項(xiàng)目的時(shí)候下愈,IDE會(huì)自動(dòng)幫我們創(chuàng)建一個(gè)名為R
的類型纽绍,它所在的文件名稱也是叫做R.java
,R
類型中沒(méi)有任何方法势似,包含的是代表不同類型資源的內(nèi)部靜態(tài)類拌夏,而這些內(nèi)部靜態(tài)類中,也只有靜態(tài)的屬性履因,每個(gè)屬性代表一個(gè)資源障簿,故我們要引用某個(gè)資源類型中的某個(gè)資源,可用R.資源類型.資源名
來(lái)引用搓逾。下面就是代碼中的實(shí)例:
// 在Activity中設(shè)置其自己的視圖布局
RootActivity.this.setContentView(R.layout.activity_root);
// 從圖片資源文件夾中加載名為"image_test"的圖片以其創(chuàng)建位圖
Bitmap aBitmap = BitmapFactory.decodeResource(this.getResources(), R.drawable.image_test);
// 以id為基準(zhǔn)找到某個(gè)視圖控件
this.showTextView = (TextView)this.findViewById(R.id.show_text_view);
巧妙的是卷谈,我們無(wú)需對(duì)R
類進(jìn)行任何的修改或定義杯拐,IDE會(huì)幫我們自動(dòng)完成:當(dāng)我們把一張圖片復(fù)制入drawable
文件夾中霞篡,R
類的drawable
內(nèi)部類會(huì)自動(dòng)聲明并定義了一個(gè)名字與圖片相同的靜態(tài)屬性,屬性的類型為int
端逼,用于對(duì)資源的唯一標(biāo)識(shí)朗兵,同樣的,當(dāng)我們創(chuàng)建一個(gè)layout
布局文件顶滩,或者在定義color
余掖、dimens
、string
的xml
配置文件中新增新配置資源礁鲁,IDE都會(huì)根據(jù)資源的改變自動(dòng)配置R
類盐欺。
iOS中的資源引用
當(dāng)我從Android轉(zhuǎn)至iOS后,我瞬間覺(jué)得iOS的資源引用略為惡心仅醇,跟Android比起來(lái)冗美,它更加蛋疼麻煩,舉幾個(gè)例子:
- 我現(xiàn)在Assets圖片庫(kù)中有一張圖片析二,名為image_test粉洼,好,我現(xiàn)在要?jiǎng)?chuàng)建一個(gè)
UIImage
對(duì)象叶摄,讓其解碼這張圖片属韧。代碼是這樣子的:
let aImage = UIImage(named: "image_test")
在這里,我使用的UIImage
構(gòu)造方法需要傳入一個(gè)字符串參數(shù)蛤吓,這個(gè)字符串要求為圖片的名字宵喂。在調(diào)用這個(gè)構(gòu)造方法的時(shí)候,我的心里有股蛋蛋的憂傷... what? 我要自己輸入一個(gè)字符串会傲,才能構(gòu)造出這個(gè)實(shí)例樊破?就算我不手打愉棱,直接復(fù)制圖片名字也好,我還要跳到Finder或者Assets中“Command + C”再回到代碼區(qū)中“Command + V”哲戚,不僅如此奔滑,UIImage(named:)
構(gòu)造方法所返回的類型是Optional
類型,原因是我在輸入圖片名字構(gòu)造的時(shí)候可能誤將名字打錯(cuò)了顺少,又或者圖片在之前不小心被我刪除了朋其,Swift不能保證構(gòu)造出的UIImage
一定非空... 略坑??
- 很多時(shí)候,我們會(huì)用到
Nib
來(lái)自定義一個(gè)視圖脆炎,比如UITableViewCell
梅猿;當(dāng)我們?cè)?code>Nib中布局配置好視圖后,我們就需要在代碼區(qū)中引用它秒裕,下面就是UITableView
注冊(cè)一個(gè)以Nib
構(gòu)建的Cell的例子:
let tableView = UITableView(frame: CGRectZero, style: .Plain)
tableView.registerNib(UINib(nibName: "TanTableViewCell", bundle: nil), forCellReuseIdentifier: ViewController.CELL_IDENTIFIER)
首先我在之前已經(jīng)創(chuàng)建好了一個(gè)名為TanTableViewCell的Nib
袱蚓,然后我們?cè)跒閁ITableViewC注冊(cè)Cell的時(shí)候,則需要以我們創(chuàng)建的Cell的Nib
文件名字符串為參數(shù)傳入UINib
的構(gòu)造方法中几蜻。這里的問(wèn)題跟上面所說(shuō)的創(chuàng)建UIImage
一樣喇潘,使用字符串作為參數(shù)構(gòu)建某些資源實(shí)例時(shí),效率會(huì)較為低下梭稚,并且由于輸入的錯(cuò)誤颖低,最終或許會(huì)導(dǎo)致實(shí)例無(wú)法構(gòu)建,這是iOS開(kāi)發(fā)API中一處蛋疼的地方弧烤。
R.Swift? 什么東東忱屑?
根據(jù)前言中關(guān)于Android資源引用的內(nèi)容,顧名思義暇昂,R.Swift
是一款基于Swift平臺(tái)莺戒,針對(duì)iOS
以及TVOS
開(kāi)發(fā)的仿Android
資源引用框架。它所針對(duì)的問(wèn)題急波,就是類似于剛剛我在上方提到的一樣从铲,避免使用字符串來(lái)構(gòu)造某些資源實(shí)例。R.Swift
能夠在我們修改項(xiàng)目資源后動(dòng)態(tài)地進(jìn)行配置幔崖,最終食店,你能夠使用類似語(yǔ)法R.資源類型.資源名稱
來(lái)對(duì)某資源進(jìn)行引用構(gòu)建。R.Swift
有著動(dòng)態(tài)生成代碼的機(jī)制赏寇,由此吉嫩,它具有以下極具魅力的優(yōu)點(diǎn):
-
代碼自動(dòng)補(bǔ)全 :就像輸入其他的代碼一樣,
R.Swift
支持IDE的代碼自動(dòng)補(bǔ)全嗅定,當(dāng)你的資源量非常龐大時(shí)自娩,你只需把資源調(diào)用語(yǔ)法的前沿部分敲出來(lái),IDE就會(huì)自動(dòng)給予代碼提示以及補(bǔ)全,這對(duì)資源的引用效率有著顯著的提高忙迁。 -
自動(dòng)檢測(cè) : 當(dāng)我們寫(xiě)入某些錯(cuò)誤的代碼時(shí)脐彩,IDE會(huì)向我們反饋錯(cuò)誤以及警告,如我們調(diào)用某個(gè)類中不存在的方法時(shí)姊扔,IDE就會(huì)立即檢測(cè)出代碼的錯(cuò)誤惠奸,并給予反饋。在
R.Swift
中恰梢,若我們將資源重命名佛南,或干脆將資源刪除了,R.Swift
會(huì)自動(dòng)重新進(jìn)行配置嵌言,而在之前我們對(duì)該資源進(jìn)行引用的地方嗅回,IDE也會(huì)相應(yīng)的向我們報(bào)錯(cuò),表明資源的不存在摧茴,如此一來(lái)绵载,我們就不必?fù)?dān)心資源的修改刪除對(duì)代碼的蝴蝶效應(yīng)了。
總之一句話苛白,R.Swift
猴犀利娃豹!
R.Swift的安裝配置
在這里我們使用的是CocoaPods
來(lái)對(duì)R.Swift
進(jìn)行安裝,相關(guān)的步驟也不必累贅說(shuō)明丸氛,一句pod install
后我們把R.Swift
安裝進(jìn)來(lái)了培愁。下面要進(jìn)行R.Swift
的配置著摔,主要有幾個(gè)步驟:
- 進(jìn)入項(xiàng)目的配置界面缓窜,在左邊的
TARGETS
項(xiàng)下面選擇我們的項(xiàng)目,并在右邊點(diǎn)擊Build Phases
這個(gè)tab谍咆。 - 進(jìn)入
Build Phases
這個(gè)tab后禾锤,我們看到左上角有一個(gè)"+"按鈕,點(diǎn)擊并在彈出的選項(xiàng)卡中選擇New Run Script Phase
摹察。 - 我們會(huì)看到界面的下方多出了一個(gè)
Run Script
項(xiàng)恩掷,展開(kāi)它,并在腳本輸入?yún)^(qū)域輸入"$PODS_ROOT/R.swift/rswift" "$SRCROOT"
(第二對(duì)雙引號(hào)括起來(lái)所代碼的是項(xiàng)目的根目錄供嚎,你也可以放到根目錄下的其他目錄中黄娘,只需將其修改為"$SRCROOT/XXX"
,XXX為目標(biāo)目錄名)克滴。 - 我們按住新建的這個(gè)
Run Script
項(xiàng)向上移動(dòng)逼争,移到Compile Source
項(xiàng)的上方,不過(guò)也要保證此時(shí)它也在Check Pods Manifest.lock
項(xiàng)的下方劝赔。 -
Command + B
誓焦,編譯一下,編譯成功后着帽,在Finder進(jìn)入到剛剛我們制定的目錄中杂伟,此時(shí)我們會(huì)看到一個(gè)名為R.generated.swift
的文件已經(jīng)創(chuàng)建了移层,直接把此文件拖入Xcode項(xiàng)目中,記住不要勾選Copy items if needed
項(xiàng)赫粥。 - 配置到此完成观话,我們可以構(gòu)建自己的項(xiàng)目了
R.Swift
對(duì)資源修改并編譯后都會(huì)在R.generated.swift
文件中自動(dòng)生成代碼,我們也可以打開(kāi)這個(gè)文件看一下現(xiàn)在資源的構(gòu)造情況越平,這里只截了一小段代碼展示:
/// This `R.font` struct is generated, and contains static references to 0 fonts.
struct font {
private init() {}
}
/// This `R.image` struct is generated, and contains static references to 1 images.
struct image {
/// Image `kafei`.
static let kafei = ImageResource(bundle: _R.hostingBundle, name: "kafei")
/// `UIImage(named: "kafei", bundle: ..., traitCollection: ...)`
static func kafei(compatibleWithTraitCollection traitCollection: UITraitCollection? = nil) -> UIImage? {
return UIImage(resource: R.image.kafei, compatibleWithTraitCollection: traitCollection)
}
private init() {}
}
/// This `R.nib` struct is generated, and contains static references to 1 nibs.
struct nib {
/// Nib `TanTableViewCell`.
static let tanTableViewCell = _R.nib._TanTableViewCell()
/// `UINib(name: "TanTableViewCell", bundle: ...)`
static func tanTableViewCell(_: Void) -> UINib {
return UINib(resource: R.nib.tanTableViewCell)
}
private init() {}
}
R.Swift的使用
在這里要說(shuō)明一下匪燕,每當(dāng)我們修改了資源,我們需要Command + B
來(lái)編譯一下項(xiàng)目從而讓R.Swift
自動(dòng)進(jìn)行配置更新喧笔。
下面就來(lái)用實(shí)例演示一下R.Swift
的使用帽驯,并與原生的API進(jìn)行比對(duì):
Image - 圖片
// 不使用R.Swift
let pImage = UIImage(named: "image_test")
// 使用R.Swift
let nImage = R.image.image_test()
File - 數(shù)據(jù)文件
// 不使用R.Swift
let pFile = NSBundle.mainBundle().pathForResource("DataFile", ofType: "json")
// 使用R.Swift
let nFile = R.file.dataFileJson.path()
Font - 字體
// 不使用R.Swift
let pFont = UIFont(name: "chalkduster", size: 35)
// 使用R.Swift
let nFont = R.font.chalkduster(size: 35)
// 你看,非常神奇书闸,在上面的方法中你不僅可以選擇字體類型尼变,還能設(shè)置字體大小
Color - 顏色
顏色這里我覺(jué)得有必要細(xì)講一下,一個(gè)較為龐大的項(xiàng)目浆劲,其顏色資源配置也是相應(yīng)比較復(fù)雜嫌术,如某些視圖的背景顏色、字體的顏色等等牌借,以往我們進(jìn)行顏色資源的配置度气,一般會(huì)定義一個(gè)全局的Config文件或類,里面就存有各種顏色膨报,每種顏色用有意義的名稱去標(biāo)識(shí)磷籍。R.Swift
與其不同的是,它還能有更贊的方式導(dǎo)入顏色資源:
Color Palette
呵呵现柠,這個(gè)方式可以說(shuō)是非常的花式院领,配合R.Swift
使用起來(lái)簡(jiǎn)直6得飛起!
當(dāng)我們?cè)诳梢暬晥D編輯界面(如Storyboard)中為一個(gè)視圖配置某些顏色時(shí)够吩,我們可以進(jìn)入顏色調(diào)色板來(lái)選擇更多的顏色比然,如圖:
在其中,我們可以創(chuàng)建自己的調(diào)色板周循,如現(xiàn)在我創(chuàng)建了一個(gè)名為
MyAppColor
的調(diào)色板:這個(gè)自定義的調(diào)色板是不局限于現(xiàn)在的項(xiàng)目强法,以后我們創(chuàng)建的每一個(gè)項(xiàng)目都可以使用這個(gè)調(diào)色板。如果你的UI設(shè)計(jì)師夠醒目的話湾笛,他也可以給我們提供一個(gè)設(shè)計(jì)師調(diào)好顏色的調(diào)色板饮怯,現(xiàn)在問(wèn)題來(lái)了,設(shè)計(jì)師在他的電腦里定義好了調(diào)色板迄本,怎么share出去呢硕淑?其實(shí)我們每自定義一個(gè)調(diào)色板,它都會(huì)以二進(jìn)制文件的形式儲(chǔ)存在電腦中,位置在
~/Library/Colors/
(隱藏文件目錄置媳,要訪問(wèn)它要不取消Finder隱藏于樟,要不直接控制臺(tái)open
跳進(jìn)來(lái)),文件的名字為調(diào)色板名.clr
拇囊,把它直接copy下來(lái)就行迂曲。R.Swift
能夠非常花式地使用調(diào)色板寥袭,有多花式路捧?就現(xiàn)在來(lái)說(shuō),我直接把我創(chuàng)建的調(diào)色板的文件
MyAppColor.clr
拖進(jìn)項(xiàng)目中传黄,Command + B
編譯下杰扫,然后,我現(xiàn)在可以這樣子得到顏色了:
let appRedColor = R.color.myAppColor.red()
簡(jiǎn)直6到飛起膘掰!??
Nib
// 不使用R.Swift
tableView.registerNib(UINib(nibName: "TanTableViewCell", bundle: nil), forCellReuseIdentifier: CELL_IDENTIFIER)
// 使用R.Swift
tableView.registerNib(R.nib.tanTableViewCell(), forCellReuseIdentifier: CELL_IDENTIFIER)
UITableView中的復(fù)用
上面的代碼讓TableView注冊(cè)了其cell所屬的Nib章姓,并輸入了cell的復(fù)用標(biāo)識(shí)符,而在另一種情況下识埋,比如我們?cè)谠O(shè)計(jì)cell的Nib時(shí)已經(jīng)在Nib中設(shè)置好了cell的復(fù)用標(biāo)識(shí)符凡伊,我們就沒(méi)必要在TableView注冊(cè)cell的時(shí)候再配置一遍了,幸虧,R.Swift
給我們提供了高效率的cell注冊(cè)以及復(fù)用方法:
- 首先在Cell的Nib中設(shè)置好復(fù)用標(biāo)識(shí)符(Identifier)
- 進(jìn)行Cell的注冊(cè)
tableView.registerNib(R.nib.tanTableViewCell)
- 編寫(xiě)TableView數(shù)據(jù)源的Cell返回方法
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier(R.nib.tanTableViewCell.identifier, forIndexPath: indexPath)
// Do Something
return cell
}
R.Swift
也支持對(duì)UICollectionView
中Cell的高效注冊(cè)與復(fù)用窒舟,方式跟UITableView
也是差不多系忙,在這里就不累贅說(shuō)明了。
以上說(shuō)明了使用R.Swift
進(jìn)行各種資源的引用構(gòu)造惠豺,除了上面的資源外银还,R.Swift
還能作用于Localized string(本地化字符串)
、Storyboards
耕腾、Segues
這些資源见剩,其大大提高了iOS開(kāi)發(fā)的資源引用構(gòu)造效率杀糯。
運(yùn)行時(shí)檢測(cè)
R.Swift
提供運(yùn)行時(shí)檢測(cè)功能扫俺,在項(xiàng)目運(yùn)行的時(shí)候能夠檢測(cè)其生成的代碼是否和此時(shí)項(xiàng)目的資源完全匹配,調(diào)用的是R.assertValid()
固翰,這個(gè)方法在release
模式下是不做任何操作的狼纬,它只作用于debug(調(diào)試)
模式,檢測(cè)的內(nèi)容為:
- 是否所有在
Storyboard
中使用的圖片都可用骂际。 - 是否所有定義在
Storyboard
中疗琉,且需要用標(biāo)識(shí)符去加載的視圖控制器都能夠成功加載。
官方建議把這個(gè)檢測(cè)方法放到項(xiàng)目的AppDelegate
中歉铝。