查找了N多資料都沒有解決啼肩。原來橄妆,類的.h頭文件和.m實現(xiàn)文件里面的方法名不一樣。給我塊豆腐我要撞死去祈坠。哈哈呼畸,但是也查了好多資料,學到了很多知識颁虐,特此分享一下蛮原。
背景
在ios開發(fā)過程中,有時候會用到第三方的靜態(tài)庫(.a文件)另绩,然后導入后發(fā)現(xiàn)編譯正常但運行時會出現(xiàn)selector not recognized的錯誤儒陨,從而導致app閃退花嘶。接著仔細閱讀庫文件的說明文檔,你可能會在文檔中發(fā)現(xiàn)諸如在Other Linker Flags中加入-ObjC或者-all_load這樣的解決方法蹦漠。
那么椭员,Other Linker Flags到底是用來干什么的呢?還有-ObjC和-all_load到底發(fā)揮了什么作用呢笛园?
鏈接器
首先隘击,要說明一下Other Linker Flags到底是用來干嘛的。說白了研铆,就是ld命令除了默認參數(shù)外的其他參數(shù)埋同。ld命令實現(xiàn)的是鏈接器的工作,詳細說明可以在終端man ld查看棵红。
如果有人不清楚鏈接器是什么東西的話凶赁,我可以作個簡單的說明。
一個程序從簡單易讀的代碼到可執(zhí)行文件往往要經(jīng)歷以下步驟:
源代碼 > 預處理器 > 編譯器 > 匯編器 > 機器碼 > 鏈接器 > 可執(zhí)行文件
源文件經(jīng)過一系列處理以后逆甜,會生成對應的.obj文件虱肄,然后一個項目必然會有許多.obj文件,并且這些文件之間會有各種各樣的聯(lián)系交煞,例如函數(shù)調用咏窿。鏈接器做的事就是把這些目標文件和所用的一些庫鏈接在一起形成一個完整的可執(zhí)行文件。
可能我描述的比較膚淺素征,因為我自己了解的也不是很深翰灾,建議大家讀一下這篇文章,可以對鏈接器做的事情有個大概的了解:鏈接器做了什么
為什么會閃退
蘋果官方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.
翻譯過來稚茅,大概意思就是Objective-C的鏈接器并不會為每個方法建立符號表纸淮,而是僅僅為類建立了符號表。這樣的話亚享,如果靜態(tài)庫中定義了已存在的一個類的分類咽块,鏈接器就會以為這個類已經(jīng)存在,不會把分類和核心類的代碼合起來欺税。這樣的話侈沪,在最后的可執(zhí)行文件中,就會缺少分類里的代碼晚凿,這樣函數(shù)調用就失敗了亭罪。
解決方法
解決方法在背景那塊我就提到了,就是在Other Linker Flags里加上所需的參數(shù)歼秽,用到的參數(shù)一般有以下3個:
-ObjC
-all_load
-force_load
下面來說說每個參數(shù)存在的意義和具體做的事情应役。
首先是-ObjC,一般這個參數(shù)足夠解決前面提到的問題,蘋果官方說明如下:
This flag causes the linker to load every object file in the library that defines an Objective-C class or category. While this option will typically result in a larger executable (due to additional object code loaded into the application), it will allow the successful creation of effective Objective-C static libraries that contain categories on existing classes.
簡單說來箩祥,加了這個參數(shù)后院崇,鏈接器就會把靜態(tài)庫中所有的Objective-C類和分類都加載到最后的可執(zhí)行文件中,雖然這樣可能會因為加載了很多不必要的文件而導致可執(zhí)行文件變大袍祖,但是這個參數(shù)很好地解決了我們所遇到的問題底瓣。但是事實真的是這樣的嗎?
如果-ObjC參數(shù)真的這么有效蕉陋,那么事情就會簡單多了捐凭。
Important: For 64-bit and iPhone OS applications, there is a linker bug that prevents -ObjC from loading objects files from static libraries that contain only categories and no classes. The workaround is to use the -allload or -forceload flags.
當靜態(tài)庫中只有分類而沒有類的時候,-ObjC參數(shù)就會失效了凳鬓。這時候茁肠,就需要使用-all_load或者-force_load了。
-all_load會讓鏈接器把所有找到的目標文件都加載到可執(zhí)行文件中村视,但是千萬不要隨便使用這個參數(shù)!假如你使用了不止一個靜態(tài)庫文件酒奶,然后又使用了這個參數(shù)蚁孔,那么你很有可能會遇到ld: duplicate symbol錯誤,因為不同的庫文件里面可能會有相同的目標文件惋嚎,所以建議在遇到-ObjC失效的情況下使用-force_load參數(shù)杠氢。
-force_load所做的事情跟-all_load其實是一樣的,但是-force_load需要指定要進行全部加載的庫文件的路徑另伍,這樣的話鼻百,你就只是完全加載了一個庫文件,不影響其余庫文件的按需加載摆尝。
最后附上一個蘋果官方對framework中使用類別温艇,并報selector not recognized 的解釋,有興趣的可以看一看:
Building Objective-C static libraries with categories
原文鏈接:http://blog.csdn.net/meegomeego/article/details/19343423