1. 程式人生 > 實用技巧 >iOS開發日常筆記(中級)

iOS開發日常筆記(中級)

iOS開發日常筆記(中級)

  1. Other Linker Flags常用的修飾詞說明:

    1. -ObjC:對於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.
      簡單的說就是ObjC會把靜態庫中所有的類和分類都連結進可執行檔案,但是它不會去檢查此類是否重複了,所以才會出現duplicate symbols的錯誤
      
    2. -force_load:這個的作用其實跟ObjC是類似的。它是隻指定某一個靜態庫才執行連結所有類和分類的操作,而ObjC表示的是所有靜態庫

    3. 開發中會遇到duplicate symbols的問題,所以理想的狀態就是不使用ObjC,只有包含分類的靜態庫才使用-force_load,這樣既能避免一些不必要的檔案使包變大,又能使出現duplicate symbols的概率減小。

      為什麼只是減小呢?因為如果你這個靜態庫裡即有重複檔案又存在分類,那隻能使用-force_load,同時那個重複的類也連結進來了,這樣duplicate symbols就還會出現

  2. 符號表和編譯鏈:

    1. 一個程式從程式碼到可執行檔案要經歷以下步驟:原始碼 > 前處理器 > 編譯器 > 彙編器 > 機器碼 > 連結器 > 可執行檔案

    2. 原始碼經過一系列處理以後,會生成對應的.o檔案,然後一個專案必然會有許多.o檔案,並且這些檔案之間會有各種各樣的聯絡,例如函式呼叫。連結器做的事就是把這些目標檔案和所用的一些庫連結在一起形成一個完整的可執行檔案;通俗的講,我們在原始碼中寫的全域性變數名函式名類名在生成的*.o物件檔案中都叫做符號,存在一個叫做符號表的地方。

    3. 舉個例子:

      1. a.c檔案中寫了一個函式叫foo(),然後在main.c檔案中呼叫了foo()函式,在將原始碼編譯(生成)的物件檔案a.o時,物件檔案中的符號表裡儲存著foo()函式符號,並通過該符號可以定位到a.o檔案中關於foo()方法的具體實現程式碼。
      2. 連結器在連結生成最終的二進位制程式的時候會發現main.o物件檔案中引用了符號foo(),而foo()符號並沒有在main.o檔案中定義,所以不會存在與main.o物件檔案的符號表中,於是連結器就開始檢查其他物件檔案,當檢查到a.o檔案中定義了符號foo(),於是就將a.o物件檔案連結進來。這樣就確保了在main.c中能夠正常呼叫a.c中實現的foo()方法了。
    4. 匯出庫裡面的符號表:nm命令,檢視庫的函式符號資訊

      1. 語法:nm [ -A ] [ -C ] [ -X {32|64|32_64}] [ -f ] [ -h ] [ -l ] [ -p ] [ -r ] [ -T ] [ -v ] [ -B | -P ] [ -e | -g | -u ] [ -d | -o | -x | -t Format ] File ...

      2. 語法說明請參考這個連結,我看寫得挺詳細的:https://blog.csdn.net/jingcheng345413/article/details/54969811

      3. 示例,列出 a.out 物件檔案的靜態和外部符號,請輸入:

        nm -e a.out
        
  3. Target Conditionals

    1. The system header TargetConditionals.h defines several macros which you can use from C and Objective-C to determine which platform you're using.
    2. The values of the macros are: 7.0 When using the iOS 9.1, tvOS 9.0, watchOS 2.0, OS X 10.11 or newer SDKs:
    Macro Mac iOS iOS simulator Watch Watch simulator TV TV simulator
    TARGET_OS_MAC 1 1 1 1 1 1 1
    TARGET_OS_IPHONE 0 1 1 1 1 1 1
    TARGET_OS_IOS 0 1 1 0 0 0 0
    TARGET_OS_WATCH 0 0 0 1 1 0 0
    TARGET_OS_TV 0 0 0 0 0 1 1
    TARGET_OS_SIMULATOR 0 0 1 0 1 0 1
    TARGET_OS_EMBEDDED 0 1 0 1 0 1 0
    TARGET_IPHONE_SIMULATOR 0 0 1 0 1 0
  4. 通過符號表還原崩潰呼叫堆資訊:

    1. 首先得有對應的xxx.dSYM檔案

    2. 找到plCrashReporter.crashlog檔案,名字可能不一樣,這個檔案源自appstore或其它第三方工具

    3. 匯出開發工具,等下需要用到,終端執行:export DEVELOPER_DIR=/Applications/Xcode.app/Contents/Developer

    4. 找到symbolicatecrash可執行檔案:路徑:/Applications/Xcode.app/Contents/SharedFrameworks/DVTFoundation.framework/Versions/A/Resources/,複製到某資料夾內,把第一步和第二步兩檔案也一起復制到同一檔案下

    5. 當然上面那一步也可以寫入終端指令碼檔案內:

      // 如我終端預設指令碼是:`.zshrc`,把下面內容追加到`.zshrc`中,這樣下次就可以省略第四步操作了
      export SYMBOLICATECRASH="/Applications/Xcode.app/Contents/SharedFrameworks/DVTFoundation.framework/Versions/A/Resources/"
      export PATH=$SYMBOLICATECRASH:$PATH
      
    6. 還原崩潰資訊:

      symbolicatecrash plCrashReporter.crashlog xxx.dSYM > appName.log
      // > 代表輸出,指定輸出的檔案:appName.log
      
    7. 常見 Exception Type 分析:

      • EXC_BAD_ACCESS:此型別的Excpetion是我們最長碰到的Crash,通常用於訪問了不改訪問的記憶體導致。一般EXC_BAD_ACCESS後面的"()"還會帶有補充資訊。

      • SIGSEGV: 通常由於重複釋放物件導致,這種型別在切換了ARC以後應該已經很少見到了。

      • SIGABRT: 收到Abort訊號退出,通常Foundation庫中的容器為了保護狀態正常會做一些檢測,例如插入nil到陣列中等會遇到此類錯誤。

      • SEGV:(Segmentation Violation),代表無效記憶體地址,比如空指標,未初始化指標,棧溢位等;

      • SIGBUS:匯流排錯誤,與 SIGSEGV 不同的是,SIGSEGV 訪問的是無效地址,而 SIGBUS 訪問的是有效地址,但匯流排訪問異常(如地址對齊問題)

      • SIGILL:嘗試執行非法的指令,可能不被識別或者沒有許可權

      • EXC_BAD_INSTRUCTION:此類異常通常由於執行緒執行非法指令導致

      • EXC_ARITHMETIC:除零錯誤會丟擲此類異常

    8. 常見 Exception Code 分析:

      • 0xbaaaaaad 此種類型的log意味著該Crash log並非一個真正的Crash,它僅僅只是包含了整個系統某一時刻的執行狀態。通常可以通過同時按Home鍵和音量鍵,可能由於使用者不小心觸發
      • 0xbad22222 當VOIP程式在後臺太過頻繁的啟用時,系統可能會終止此類程式
      • 0x8badf00d 程式啟動或者恢復時間過長被watch dog終止
      • 0xc00010ff 程式執行大量耗費CPU和GPU的運算,導致裝置過熱,觸發系統過熱保護被系統終止
      • 0xdead10cc 程式退到後臺時還佔用系統資源,如通訊錄被系統終止
      • 0xdeadfa11 前面也提到過,程式無響應使用者強制關閉