深度解析iPhone Category用法是本文要介紹的內容,在開發3.0的iPhone靜態庫的時候,遇到了一些問題。儘管我在應用程式連結的選項裡頭使用-ObjC的選項,我的程式在iPhone上運行時還是Crash了,而且經過定位之後發現,還是由庫中的Category相關方法沒有被鏈入導致的;而程式在模擬器上運行卻是一點問題沒有,Category的相關方法都能正確得到執行。
那麼到底是什麼原因導致在真機上應用程式沒有將Category方法鏈入呢?答案還是在上次提到的這個蘋果官方網頁。該網頁下方的IMPORTANT裡頭提到,在64位及iPhone OS系統裡,由於編譯器的Bug導致了-ObjC選項無法正常將靜態庫中的類的Category的方法載入!也就是說,
假設你的類叫MyClass,並且另外有個Category叫MyClass(Extent),那麼如果你的應用程式連結你的庫,使用MyClass(Extent)中的方法,程式將會Crash!要提的是,如果你的MyClass(Extent) 的實現是和MyClass的實現是在同一個實現體中,那麼該Category的方法還是可以正常使用的,因為編譯的時候會一起被載入。
那麼,假設你的庫已經使用了Category,最後要使用放到真機上的時候發現,他Crash了!那該怎麼辦呢?除了改代碼,還是有一些補救方法的。
第一種,官方推薦的,但往往不是很好用的。使用-all_load選項,這會導致所有的類的方法都會被載入,不管“你的程式”有沒有用到,所有的,包括系統的,方法會被載入。這個方法不僅會導致你的目標程式大小增大,而且往往容易引起一些衝突,而這些衝突往往你無法解決常常出現在你連結的各種庫中)。或者你可以使用-force_load,這個你可以指定要載入所有方法的庫,這個算一個還不錯的解決方案,但是僅在Xcode3.2之後才支援,如果你必須支援低版本的SDK的話,那麼很悲劇,您這兩種方法都不大適用!悲劇如我,就是這種情況)
第二種,你使用的Category是你自己的類的Category,這是個常見的情況,自己的一個類比較大,分拆成多個檔案時常用的手段。經過一段時間的思考,發現這種情況的解救方法還是比較容易的,雖然個人認為有點不優雅,但是可以很簡單的解決掉。
你可以將你所有的Category的標頭檔包含到類的主標頭檔或者主實現檔案中,並且直接在你的類的主實現檔案中去import你的各個Category的實現檔案。這樣,編譯器在鏈入你的類的主方法時,你的各個Category實現由於被import到你的類主實現檔案中,所以他可以找到你的Category方法,並將該方法鏈入目標檔案。當然,這個方法不太優雅就是了。
第三種,就是你使用的是系統API某個類的Category,比如你為UILabel增加了個Category:UILabel(MyExtent).這個其實也很麻煩,剛開始也試了很多方法,網上的一些方法也試過,但是貌似還是不管用,最後換了個想法想,這個和自己類的Category有什麼區別,貌似一樣沒區別阿。所以最後試了一下,只要找一個必定會使用的類,將Category的標頭檔和實現檔案import到該類的主實現檔案中,這樣編譯器就也能找到這些Category方法了。雖然一樣解決了問題,還是那句話,一點都不優雅!
雖然最後終雩都解決了這些問題,得出的結論還是,不要輕易在iPhone3.0及3.0以上的靜態庫中使用分檔案的Category方法。但2.0的SDK編譯的實驗過無問題。
最後的吐槽是:Category作為一個Objective-C最特色的文法功能之一,居然無法正常的在靜態庫中使用,蘋果你不覺得你很過分嗎!這麼嚴重的bug也不修複!你難道逼我寫個1000行左右的類嗎?有些類由於某些原因不一定是技術原因)是不允許分拆成不同的類名!
小結:深度解析iPhone Category用法的內容介紹完了,希望本文對你有所協助!