不少人在開發中都會遇到 EXC_BAD_ACCESS ,很遺憾,這一次 Xcode 不會給出任何詳細的解決方案。
通常來說,這是由於內存錯誤造成的。簡單來說就是你創建了對象 A,但在後來訪問的時候,內存裡 A 這塊區域已經被系統挪做他用了,比如放了對象 B 在這裡——你的 A 只剩下指針,實際內容已經不存在了。
這時就會出現類似這樣的崩潰:
1 |
-[__NSCFType dismissAuxiliaryWindows]: unrecognized selector sent to instance 0x6000030010e0 |
由於實際對像已經變更,Swift 編譯器卻並不知道,結果自然就是一個“未知的 Selector”了。
嘗試解決它
一開始,無知的我想要去找到這個“instance”到底是誰,於是我開始用這個方法打印程序裡的對象:
1 2 |
var a = 1 print(Unmanaged.passUnretained(a).toOpaque()) |
嗯,後來我發現這是一個無止境的工作……但報錯變得有意思了:
1 |
-[_TtGCs23_ContiguousArrayStorageSS_$ dismissAuxiliaryWindows]: unrecognized selector sent to instance 0x600003004240 |
這讓我更加摸不著頭腦。
再後來,乾脆就沒報錯了,就是 EXC_BAD_ACCESS ,於是內存地址對比也就到此為止了……
正確的做法
總之,Xcode 還是有工具來處理這種情況的——雖然不一定是百發百中,但至少能增加一點排錯的線索,我們到 Xcode 左上角選擇 Edit Scheme,編輯當前程序的執行選項:
在打開的頁面選“Run”,選右側“Diagnosis”選項卡,勾選下方的“Zombie Object”。
Zombie Object 模式:殭屍模式,在這個模式下你的程序不會真的釋放需要被釋放的內存,即使對象 A 已經沒有引用,它也會被保留在內存當中,這樣就避免了系統將其他對象的內存寫到同一位置,一旦 EXC_BAD_ACCESS 發生,Xcode 將能夠發現程序原本想要訪問的是哪個對象。
再次運行程序,觸發崩潰,我們得到了新的報錯:
1 |
*** -[NSSpellChecker dismissAuxiliaryWindows]: message sent to deallocated instance 0x600003010b40 |
顯然,這次就明確多了,雖然不知為何,但這次的 EXC_BAD_ACCESS 是由於程序訪問了一個 NSSpellChecker 對象導致的,這下就大大縮小了排錯範圍,運氣好的話應該很快就能定位問題所在了。
總之,最終記得關閉這個模式,不然程序佔用內存會無休止地增加下去……
參考文獻
本文由 落格博客 原創撰寫:落格博客 » 斯威夫特調試EXC_BAD_ACCESS中的AppDelegate
轉載請保留出處和原文鏈接:https://www.logcg.com/archives/3313.html