原文地址: http://nszzy.me/2015/10/18/crash-with-static-library/
使用其他一些第三方靜態(tài)庫(kù)時(shí), 如果沒(méi)有注意按照文檔中的提示進(jìn)行配置, 很容易在程序運(yùn)行過(guò)程中因 "unrecorgnized selector send to instance xxx" 的異常而崩潰. 而且可以發(fā)現(xiàn), 導(dǎo)致崩潰的方法都是Category中的方法.
在蘋果官方文檔中解釋到:
The dynamic nature of Objective-C complicates things slightly. Because the code that implements a method is not determined until the method is actually called, Objective-C does not define linker symbols for methods. Linker symbols are only defined for classes.
Since categories are a collection of methods, using a category's method does not generate an undefined symbol. This means the linker does not know to load an object file defining the category, if the class itself is already defined. This causes the same "selector not recognized" runtime exception you would see for any unimplemented method.
翻譯過(guò)來(lái), 就是因?yàn)镺bjective-C的動(dòng)態(tài)特性使得方法是在運(yùn)行時(shí)才確定的, 所以鏈接的時(shí)候不會(huì)為方法(Method)定義連接符號(hào), 而是為類(Class)定義連接符號(hào). 這樣當(dāng)在一個(gè)靜態(tài)庫(kù)中使用類別來(lái)擴(kuò)展已有類的時(shí)候,鏈接器不知道如何把類原有的方法和類別中的方法整合起來(lái), 所以就導(dǎo)致運(yùn)行的時(shí)候Category的方法無(wú)法被找到拋出異常.
解決方法:
Other Linker Flags
-
-ObjC
蘋果官方文檔對(duì)這個(gè)flag的解釋是這樣的:
Passing the -ObjC option to the linker causes it to load all members of static libraries that implement any Objective-C class or category. This will pickup any category method implementations. But it can make the resulting executable larger, and may pickup unnecessary objects. For this reason it is not on by default.
-ObjC
這個(gè)標(biāo)志選項(xiàng)會(huì)讓鏈接器加載靜態(tài)庫(kù)所有的Objective-C的類和Category, 這樣就能把Category中實(shí)現(xiàn)的方法整合起來(lái). 但是由于這樣做會(huì)使可執(zhí)行文件變大, 也會(huì)整合一些用不到的對(duì)象, 所以才沒(méi)有默認(rèn)使用-ObjC標(biāo)志, 而是需要我們手動(dòng)添加.
-
-all_load
加載所有靜態(tài)庫(kù)中的文件. 相比-ObjC
, 不同點(diǎn)就是-all_load
會(huì)將所有的(包括非Objective-C)文件都整合到靜態(tài)庫(kù)中.
*注意 : 假如你使用了不止一個(gè)靜態(tài)庫(kù),然后又使用了這個(gè)參數(shù),那么你很有可能會(huì)遇到duplicate symbol
錯(cuò)誤,因?yàn)椴煌膸?kù)文件里面可能會(huì)有相同的目標(biāo)文件.
-
-force_load (path_to_archive)
加載指定路徑的靜態(tài)庫(kù). 相比-all_load
, 不同點(diǎn)就是-force_load
只是完全加載了一個(gè)庫(kù)文件,不影響其余庫(kù)文件的按需加載.
補(bǔ)充:
使用-all_load
或者-force_load
大部分原因是因?yàn)?strong>Xcode4.2之前的版本的鏈接器的bug, 在64位iOS應(yīng)用環(huán)境下當(dāng)靜態(tài)庫(kù)中只有分類而沒(méi)有類的時(shí)候, -ObjC
參數(shù)就會(huì)失效了. 所以為了兼容Xcode4.2之前的版本, 有兩種解決方法:
靜態(tài)庫(kù)使用者:
使用-all_load
或者-force_load
代替-ObjC
.靜態(tài)庫(kù)開發(fā)者:
可以通過(guò)在分類中添加一個(gè)類的聲明和實(shí)現(xiàn), 使得Category源文件中不僅僅只有分類, 同時(shí)還有類存在來(lái)避免鏈接器的bug, 從而避免了-ObjC
標(biāo)志失效的麻煩:
/**
* NSObject+Addition.m
*/
// add a dummy class
@interface DUMMY_CLASS_NSObject_Addition : NSObject
@end
@implementation DUMMY_CLASS_NSObject_Addition
@end
@implementation NSObject (Addition)
// some category methods...
@end
但是Xcode4.2之后, 只要使用-ObjC
即可. 具體可以參看stackoverflow的這個(gè)回答.