一款監控子執行緒操縱 UI 的能力,也可以新增自定義的 API 進行監控(實現在子執行緒監控某些 API 的時候捕獲具體堆疊資訊,幫助定位問題)
背景介紹
可能有些人一直沒有遇到過因為在子執行緒操作 UI,導致在開發階段 Xcode console 輸出了一堆日誌,大體如下
其實我們可以給 Xcode 打個 Runtime Issue Breakpoint
,type 選擇 Main Thread Checker
, 在發生子執行緒操作 UI 的時候就會被系統檢測到並觸發斷點,同時可以看到堆疊情況
效果如下
問題及解決方案
上述的功能是在 Xcode 自帶的,連線 Xcode 做除錯才具備的功能,線上包無法檢測到。
經過探索 Xcode 實現該功能是依賴於裝置上的 libMainThreadChecker.dylib
庫,我們可以通過 dlopen
方法強制載入該庫讓非 Xcode 環境下也擁有監測功能。
另外在監控到子執行緒呼叫 UI 呼叫時,在 Xcode 環境下,會將呼叫棧輸出到控制檯,經過測試,libMainThreadChecker.dylib
使用的是進行輸出的,由於 NSLog 是將資訊輸出到 STDERR
中,我們可以通過 NSPipe
與 dup2
將 STDERR
輸出攔截,通過對資訊的文案的判斷,進而獲取監測到的 UI 呼叫,最後可以通過堆疊列印出來,就可以幫助定位到具體問題。
libMainThreadChecker.dylib
庫具有侷限性,僅僅對系統提供的一些特定類的特定 API 在子執行緒呼叫會被監控到(例如 UIKit 框架中 UIView 類)。
但是某些類有些 API 我們也不希望在子執行緒被呼叫,這時候 libMainThreadChecker.dylib
是無法滿足的。
對 libMainThreadChecker.dylib
庫的彙編程式碼研究,發現 libMainThreadChecker.dylib
是通過內部 __main_thread_add_check_for_selector
這個方法來進行類和方法的註冊的。所以如果我們同樣可以通過 dlsym
來呼叫該方法,以達到對自定義類和方法的主執行緒呼叫監測。
另外該功能可以線上下 debug 階段開啟,判斷是否是在 Xcode debug 狀態,可以通過蘋果提供的官方判斷方法實現。
對 dlopen、dlsym 陌生的小夥伴可以直接看 Apple 官方文件,這裡不做展開。
APM 合集
對於 APM 感興趣的小夥伴可以檢視這篇帶你打造一套 APM 監控系統的文章