"民之失德耕肩,乾糇以愆;他山之石问潭,可以攻玉猿诸。"? - 《詩(shī)經(jīng)》
在開(kāi)發(fā) iOS 應(yīng)用時(shí),可能遇見(jiàn)這樣的情況:你想實(shí)現(xiàn)的某種功能(比如崩潰收集)狡忙,已經(jīng)有成熟的產(chǎn)品提供梳虽,可行的方案就是集成這個(gè)使用了很久,且有專(zhuān)業(yè)人員維護(hù)去枷,最重要的是“免費(fèi)”的產(chǎn)品怖辆。一番折騰之后,運(yùn)行時(shí)有可能出現(xiàn)"selector not recognized"錯(cuò)誤删顶,最后發(fā)現(xiàn)是少了如下的配置(Build Settings -> "-ObjC"):
那么這個(gè)"–ObjC" 到底是個(gè)什么鬼竖螃? 我們來(lái)扒一扒。
"-ObjC" 的使用場(chǎng)景
據(jù)坊間說(shuō):如果你集成了有 category 的靜態(tài)庫(kù)逗余,有可能出現(xiàn)上述錯(cuò)誤特咆。原因就是:Technical Q&A QA1490
"An impedance mismatch between UNIX static libraries and the dynamic nature of Objective-C can cause category methods in static libraries to not be linked into an app, resulting in "selector not recognized" exceptions when the methods aren't found at runtime."
這段話的意思就是:鏈接器在處理包含Category方法的UNIX的靜態(tài)庫(kù)時(shí),沒(méi)有將Category的方法鏈接到APP中录粱,造成這個(gè)錯(cuò)誤腻格。具體的細(xì)節(jié)在本文的補(bǔ)充部分展開(kāi)。
可以看出啥繁,解決這個(gè)錯(cuò)誤的方法就是:將Category的方法鏈接到APP中菜职,這樣APP運(yùn)行時(shí),就能夠找到對(duì)應(yīng)的selector旗闽。而 –ObjC就可以完成這個(gè)任務(wù)酬核。
"-ObjC"的作用是:將靜態(tài)庫(kù)中任何Objective-C代碼都鏈接到APP中蜜另。任何Objective-C代碼當(dāng)然也包括Category的方法〉找猓可以看出举瑰,使用-ObjC可能會(huì)鏈接很多靜態(tài)庫(kù)中未被使用的Objective-C代碼,極大的增加APP的代碼體積蔬螟。
"-ObjC" 的兄弟
和 "-ObjC"作用類(lèi)似的有以上的五種方案此迅。可以看出旧巾,從增加APP代碼體積來(lái)看耸序,偽符號(hào)方案增加得最少"Perform Single-Object Prelink"、 "-force_load" 和 "–ObjC" 次之菠齿,"-all_load" 增加得最多佑吝。
在開(kāi)發(fā)iOS SDK時(shí),為了方便使用者手動(dòng)集成绳匀,最好是減少使用者需要配置的信息,所以"偽符號(hào)"方案和 "Perform Single-Object Prelink"方案是推薦的炸客。另外疾棵,第三方SDK常常是閉源的,對(duì)于使用者來(lái)說(shuō)痹仙,偽符號(hào)是透明的是尔,所以從簡(jiǎn)便性角度看,推薦"Perform Single-Object Prelink"方案开仰。
"selector not recognized"錯(cuò)誤的產(chǎn)生根源
iOS工程拟枚,從源文件到生成最終的APP文件鹉动,通常要經(jīng)過(guò)如下步驟:
源文件經(jīng)過(guò)編譯和優(yōu)化后桃纯,會(huì)生成目標(biāo)代碼。目標(biāo)代碼中包括符號(hào)表寺酪,標(biāo)示了此代碼中的全局符號(hào)和靜態(tài)符號(hào)谓娃,還標(biāo)示了導(dǎo)入符號(hào)等脚乡,鏈接器會(huì)根據(jù)符號(hào)表分析各個(gè)目標(biāo)代碼之間的調(diào)用關(guān)系,然后將使用到的代碼進(jìn)行鏈接和重定位滨达,最后生成可執(zhí)行文件奶稠。
在編譯Objective-C源文件到目標(biāo)文件時(shí),編譯器并不知道方法的對(duì)應(yīng)實(shí)現(xiàn)捡遍,只能在運(yùn)行時(shí)才知道锌订,所以編譯器只會(huì)為類(lèi)生成鏈接符號(hào),對(duì)類(lèi)中的方法不會(huì)生成鏈接符號(hào)画株。由于Category方法并不對(duì)應(yīng)一個(gè)新類(lèi)辆飘,所以不會(huì)生成鏈接符號(hào)涩搓,鏈接器也不會(huì)將Category方法合并到原始的類(lèi)中,最終導(dǎo)致鏈接器忽略了Category方法劈猪,不會(huì)將其鏈接到可執(zhí)行文件中昧甘。