事情背景
這個坑是前幾天踩的砸民,踩的還特別是時候項目馬上要發(fā)版了喷众,發(fā)給測試做最后的驗證,測試反饋從log上面看有點詭異莺债,有些手機可以有些手機不可以滋觉。因為提測前我是做過自測的,我相信應(yīng)該沒有問題齐邦,一同和測試一起繼續(xù)測試椎侠,發(fā)現(xiàn)還是有些手機可以有些手機不可以。這么奇怪的問題讓我很懵逼呀措拇。按照常理來說應(yīng)該是要不可以就都不可以呀我纪。因為這是一個請求里面發(fā)生的當時我的本能反應(yīng)是不是網(wǎng)絡(luò)不穩(wěn)定呀,但是話又說會來。這如果是網(wǎng)絡(luò)的問題的話也不會這么巧合呢宣羊?好吧 我又回到座位開始吭哧吭哧的查bug了璧诵,說好的發(fā)完版去健身的,啊啊啊又要泡湯了仇冯;因為最近肩膀又開始疼痛了(ps 程序員請保護好自己的身體)之宿,今天特意寫了一個demo來追蹤下原因。(普通的程序員解決問題苛坚,優(yōu)秀的程序員追溯問題的根源比被,這句話好像哪里有點不太對,開始查找原因吧)泼舱。
問題排查
log全開等缀,手機全部部署上看log,剛剛有問題的手機也沒有問題呀娇昙。我的哥尺迂,這什么情況。百思不得其解冒掌。然后又用發(fā)布demo測試了下噪裕,一看好像還真不行。我的天報異常了股毫。
這是什么鬼膳音,我明明寫了這個方法呀,為啥會說找不到呢铃诬。測試一直問我你是不是給我同樣的包呀祭陷,為啥之前可以現(xiàn)在不可以。我 我 我開始懷疑人生了趣席。我保證我真的沒有改過任何代碼除了關(guān)閉log兵志。雖然問題找到了但是我還是不知道為啥會這樣。想了很久沒明白為啥會這樣呢吩坝《疽蹋可事實擺在面前呀哑蔫,就是報異常了钉寝。吃完飯回來,突然想到好像有點不一樣闸迷。之前給測試的包我是直接把sdk的工程直接引入到測試demo的嵌纲。如下圖
我相信很多sdk的開發(fā)者測試的時候應(yīng)該都是這么玩的,因為這樣便于調(diào)試sdk的問題腥沽〈撸可是對外demo里面我引用的是靜態(tài).a庫。
這是我目前唯一能想到的差別了今阳。一測還真是师溅,只有引入靜態(tài)庫的時候才會出問題茅信,那問題應(yīng)該是靜態(tài)庫在打包的時候這個方法沒有被添加到被擴展的類里面。這個報錯的這個方法是很特別的墓臭,因為我為了通用所以就使用category特性擴展了NSString蘸鲸。網(wǎng)上一查在靜態(tài)庫中還真有問題,從文章中的原因我們可以看出是:
Unix的標準靜態(tài)庫實現(xiàn)和Objective-C的動態(tài)特性之間有一些沖突:Objective-C沒有為每個函數(shù)(或者方法)定義鏈接符號窿锉,它只為每個類創(chuàng)建鏈接符號酌摇。這樣當在一個靜態(tài)庫中使用類別來擴展已有類的時候,鏈接器不知道如何把類原有的方法和類別中的方法整合起來嗡载,就會導致你調(diào)用類別中的方法時窑多,出現(xiàn)"selector not recognized",也就是找不到方法定義的錯誤洼滚。為了解決這個問題埂息,引入了-ObjC標志,它的作用就是將靜態(tài)庫中所有的和對象相關(guān)的文件都加載進來
這就是問題的根源遥巴。但是另外一篇文章中說在64位的操作體統(tǒng)中鏈接器有一個bug耿芹,會導致只包含有類別的靜態(tài)庫無法使用-ObjC標志來加載文件。變通方法是使用-all_load 或者-force_load標志挪哄,它們的作用都是加載靜態(tài)庫中所有文件吧秕,不過all_load作用于所有的庫,而-force_load后面必須要指定具體的文件迹炼。
尋找真兇
對于我上面的描述大家可能會認為問題的根源是我的不同引用方式造成的砸彬,直到我剛剛寫這個demo之前我也一直這么認為的。但是事實真的是這樣嗎斯入? NO ,事情的真相是我的開發(fā)demo里面增加了-ObjC標志砂碉,發(fā)布demo里面沒有。這才是真正的原因刻两。因為在我剛剛寫CategoryExtendDemo的時候我發(fā)現(xiàn)不管我是直接引入工程還是引入靜態(tài)庫都會拋出異常增蹭。所以說明這兩種引用方式?jīng)]問題。 上面的兩篇文章說了是沒有增加-ObjC標志的原因磅摹。果真我在我的測試demo里面增加這個標志之后兩種方式都不會出問題滋迈。看來這才是真正的原因户誓。果然我在我的開發(fā)demo里面也發(fā)現(xiàn)了我確實增加了-ObjC標志饼灿。
為了進一步測試如果擴展了自定義的類是否也會有同樣的問題,我在代碼里面測試了一個自定義的類
@interface CustomCategory : NSObject
@end
@implementation CustomCategory
@end
//擴展類
@interface CustomCategory(Extend)
- (void)extendMethod;
@end
@implementation CustomCategory(Extend)
- (void)extendMethod{
NSLog(@"CustomCategory extendMethod");
}
@end
總結(jié)
1帝美、在靜態(tài)庫中如果我們使用了category擴展方法碍彭,不管是系統(tǒng)的還是自定義的類如果沒有添加-Objc相關(guān)標志,都會拋出unrecognized selector sent to instance 異常。
2庇忌、在測試sdk的時候一定要和發(fā)布包操作環(huán)境一樣舞箍,不然真的不知道哪個環(huán)節(jié)坑了自己,最重要的是還坑了隊友皆疹。
3创译、在sdk這種要提供給第三方使用的代碼里面減少使用category這種類似黑科技的特性,因為我們不能確保用戶會增加-ObjC鏈接標志,因為如果我們只是在靜態(tài)庫編譯的時候加上這個標志墙基,用戶沒有加上也同樣會拋出異常软族。