子執行緒 UI 問題捉蟲

fantasticbaby發表於2022-02-07

一款監控子執行緒操縱 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中,我們可以通過 NSPipedup2STDERR 輸出攔截,通過對資訊的文案的判斷,進而獲取監測到的 UI 呼叫,最後可以通過堆疊列印出來,就可以幫助定位到具體問題。

libMainThreadChecker.dylib 庫具有侷限性,僅僅對系統提供的一些特定類的特定 API 在子執行緒呼叫會被監控到(例如 UIKit 框架中 UIView 類)。
但是某些類有些 API 我們也不希望在子執行緒被呼叫,這時候 libMainThreadChecker.dylib是無法滿足的。

libMainThreadChecker.dylib 庫的彙編程式碼研究,發現 libMainThreadChecker.dylib 是通過內部 __main_thread_add_check_for_selector 這個方法來進行類和方法的註冊的。所以如果我們同樣可以通過 dlsym 來呼叫該方法,以達到對自定義類和方法的主執行緒呼叫監測。

另外該功能可以線上下 debug 階段開啟,判斷是否是在 Xcode debug 狀態,可以通過蘋果提供的官方判斷方法實現。

dlopendlsym 陌生的小夥伴可以直接看 Apple 官方文件,這裡不做展開。

APM 合集

對於 APM 感興趣的小夥伴可以檢視這篇帶你打造一套 APM 監控系統的文章

相關文章