使用場景
<p> 在ios開發(fā)中某筐,我們經(jīng)常會(huì)使用到第三方的一些靜態(tài)庫,導(dǎo)入第三方類庫運(yùn)行程序后你會(huì)發(fā)現(xiàn),編譯時(shí)可以正常編譯但是運(yùn)行時(shí)會(huì)app會(huì)閃退,報(bào)出selector not recognized的錯(cuò)誤踪央。一般的第三方庫的開發(fā)文檔中都會(huì)寫出這種問題的解決方法,如在Other Linker Flags中加入-ObjC或者-all_load或者-force_load這樣的解決方法胳喷。為什要這要做呢?報(bào)錯(cuò)為什么編譯的時(shí)候有問題呢,首先我們先引入一個(gè)鏈接器的概念.</p>
鏈接器
<p>
還記得我們在學(xué)習(xí)C程序的時(shí)候排抬,從C代碼到可執(zhí)行文件經(jīng)歷的步驟是:
</p>
源代碼 > 預(yù)處理器 > 編譯器 > 匯編器 > 機(jī)器碼 > 鏈接器 > 可執(zhí)行文件
在最后一步需要把.o文件和C語言運(yùn)行庫鏈接起來铐姚,這時(shí)候需要用到ld命令痪伦。源文件經(jīng)過一系列處理以后残制,會(huì)生成對應(yīng)的.obj文件苫纤,然后一個(gè)項(xiàng)目必然會(huì)有許多.obj文件碉钠,并且這些文件之間會(huì)有各種各樣的聯(lián)系,例如函數(shù)調(diào)用卷拘。鏈接器做的事就是把這些目標(biāo)文件和所用的一些庫鏈接在一起形成一個(gè)完整的可執(zhí)行文件
通過這個(gè)流程你也應(yīng)該知道為什么在編譯的過程中沒事而在運(yùn)行的時(shí)候就會(huì)報(bào)錯(cuò)了. 那我們?yōu)槭裁匆O(shè)置Other Linker Flags呢 因?yàn)镺ther Linker Flags其實(shí)就是鏈接器工作時(shí)除了默認(rèn)參數(shù)外的其他參數(shù)喊废。
閃退的原因
蘋果官方Q&A上有這么一段話:
The "selector not recognized" runtime exception occurs due to an issue between the implementation of standard UNIX static libraries, the linker and the dynamic nature of Objective-C. Objective-C does not define linker symbols for each function (or method, in Objective-C) - instead, linker symbols are only generated for each class. If you extend a pre-existing class with categories, the linker does not know to associate the object code of the core class implementation and the category implementation. This prevents objects created in the resulting application from responding to a selector that is defined in the category.
翻譯:運(yùn)行時(shí)的異常時(shí)由于靜態(tài)庫,鏈接器,與OC語言的動(dòng)態(tài)的特性之間的問題,OC語言并不是對每一個(gè)函數(shù)或者方法建立符號表,而只是對每一個(gè)類創(chuàng)建了符號表.如果一個(gè)類有了分類,那么鏈接器就不會(huì)將核心類與分類之間的代碼完成進(jìn)行合并,這就阻止了在最終的應(yīng)用程序中的可執(zhí)行文件缺失了分類中的代碼,這樣函數(shù)調(diào)用接失敗了.
other linker flags參數(shù)的作用
在前面我們說如果出現(xiàn)問題要在Other Linker Flags中加入-ObjC或者-all_load或者-force_load,我們?yōu)槭裁匆尤脒@樣的參數(shù)呢,他們究竟做了什么事呢?下面就是對這個(gè)三個(gè)參數(shù)的一個(gè)講解.
ObjC
一般這個(gè)參數(shù)足夠解決前面提到的問題,這個(gè)flag告訴鏈接器把庫中定義的Objective-C類和Category都加載進(jìn)來。這樣編譯之后的app會(huì)變大,因?yàn)榧虞d了很多不必要的文件而導(dǎo)致可執(zhí)行文件變大栗弟。但是如果靜態(tài)庫中有類和category的話只有加入這個(gè)flag才行,但是Objc也不是萬能的,當(dāng)靜態(tài)庫中只有分類而沒有類的時(shí)候,Objc就失效了,這就需要使用-all_load或者-force_load了污筷。
-all_load
-all_load會(huì)強(qiáng)制鏈接器把目標(biāo)文件都加載進(jìn)來,即使沒有objc代碼乍赫。但是這個(gè)參數(shù)也有一個(gè)弊端,那就是你使用了不止一個(gè)靜態(tài)庫文件瓣蛀,那么你很有可能會(huì)遇到ld: duplicate symbol錯(cuò)誤,因?yàn)椴煌膸煳募锩婵赡軙?huì)有相同的目標(biāo)文件 這里會(huì)有兩種方法解決 1:用命令行就行拆包. 2:就是用下面的這個(gè)參數(shù)
-force_load
這個(gè)flag所做的事情跟-all_load其實(shí)是一樣的雷厂,只是-force_load需要指定要進(jìn)行全部加載的庫文件的路徑惋增,這樣的話,你就只是完全加載了一個(gè)庫文件改鲫,不影響其余庫文件的按需加載 .
總結(jié)
個(gè)人建議ObjC與force_load搭配使用比較好.