關於Xcode的Other Linker Flags

連接器

首先,要說明一下Other Linker Flags究竟是用來幹嗎的。說白了,就是ld命令除了默認參數外的其餘參數。ld命令實現的是連接器的工做,詳細說明能夠在終端man ld查看。php

若是有人不清楚連接器是什麼東西的話,我能夠做個簡單的說明。app

一個程序從簡單易讀的代碼到可執行文件每每要經歷如下步驟:函數

源代碼 > 預處理器 > 編譯器 > 彙編器 > 機器碼 > 連接器 > 可執行文件this

源文件通過一系列處理之後,會生成對應的.obj文件,而後一個項目必然會有許多.obj文件,而且這些文件之間會有各類各樣的聯繫,例如函數調用。連接器作的事就是把這些目標文件和所用的一些庫連接在一塊兒造成一個完整的可執行文件。spa

可能我描述的比較膚淺,由於我本身瞭解的也不是很深,建議你們讀一下這篇文章,能夠對連接器作的事情有個大概的瞭解:連接器作了什麼.net

爲何會閃退

蘋果官方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.code

翻譯過來,大概意思就是Objective-C的連接器並不會爲每一個方法創建符號表,而是僅僅爲類創建了符號表。這樣的話,若是靜態庫中定義了已存在的一個類的分類,連接器就會覺得這個類已經存在,不會把分類和核心類的代碼合起來。這樣的話,在最後的可執行文件中,就會缺乏分類裏的代碼,這樣函數調用就失敗了。ci

解決方法

解決方法在背景那塊我就提到了,就是在Other Linker Flags里加上所需的參數,用到的參數通常有如下3個:get

  • -ObjC

  • -all_load

  • -force_load

下面來講說每一個參數存在的意義和具體作的事情。

首先是-ObjC,通常這個參數足夠解決前面提到的問題,蘋果官方說明以下:

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.

簡單說來,加了這個參數後,連接器就會把靜態庫中全部的Objective-C類和分類都加載到最後的可執行文件中,雖然這樣可能會由於加載了不少沒必要要的文件而致使可執行文件變大,可是這個參數很好地解決了咱們所遇到的問題。可是事實真的是這樣的嗎?

若是-ObjC參數真的這麼有效,那麼事情就會簡單多了。

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.

當靜態庫中只有分類而沒有類的時候,-ObjC參數就會失效了。這時候,就須要使用-all_load或者-force_load了。

-all_load會讓連接器把全部找到的目標文件都加載到可執行文件中,可是千萬不要隨便使用這個參數!假如你使用了不止一個靜態庫文件,而後又使用了這個參數,那麼你頗有可能會遇到ld: duplicate symbol錯誤,由於不一樣的庫文件裏面可能會有相同的目標文件,因此建議在遇到-ObjC失效的狀況下使用-force_load參數。

-force_load所作的事情跟-all_load實際上是同樣的,可是-force_load須要指定要進行所有加載的庫文件的路徑,這樣的話,你就只是徹底加載了一個庫文件,不影響其他庫文件的按需加載。

相關文章
相關標籤/搜索