iOS崩潰是讓iOS開發(fā)人員比較頭痛的事情弓柱,app崩潰了,說明代碼寫的有問題痊乾,在這里了解一下XCode用來表示各種崩潰類型的術(shù)語喘批,補(bǔ)充一些這方面的各知識撩荣。崩潰通常是指操作系統(tǒng)向正在運(yùn)行的程序發(fā)送的信號,所以我們在查看崩潰日志時(shí)饶深,常巢筒埽看到如下錯(cuò)誤摘要:Application received signal SIGSEGV。一般來說粥喜,常見的崩潰類型有以下幾種:
一凸主、EXC_BAD_ACCESS
野指針引起的崩潰橘券,訪問了一個(gè)已經(jīng)釋放的內(nèi)存而導(dǎo)致额湘,向已經(jīng)釋放的對象或向它發(fā)送消息時(shí),EXC_BAD_ACCESS就會出現(xiàn)旁舰。造成EXC_BAD_ACCESS最常見的原因是锋华,在初始化方法中初始化變量時(shí)用錯(cuò)了所有權(quán)修飾符,這會導(dǎo)致對象過早地被釋放箭窜。舉個(gè)例子毯焕,在viewDidLoad方法中為UIViewController創(chuàng)建了一個(gè)包含元素的NSArray,卻將該數(shù)組的所有權(quán)修飾符設(shè)成了assign而不是strong』怯#現(xiàn)在在viewWillAppear中纳猫,若要訪問已經(jīng)釋放掉的對象時(shí),就會得到名為EXC_BAD_ACCESS的崩潰竹捉。
這個(gè)崩潰發(fā)生時(shí)芜辕,查看崩潰日志,卻往往得不到有用的棧信息块差。還好侵续,有一個(gè)方法用來解決這個(gè)問題:NSZombieEnabled倔丈。
這是一個(gè)環(huán)境變量,用來調(diào)試與內(nèi)存相關(guān)的問題状蜗,跟蹤對象的釋放過程需五。啟用了NSZombieEnabled的話,它會用一個(gè)僵尸實(shí)現(xiàn)來去你的默認(rèn)的dealloc實(shí)現(xiàn)轧坎,也就是在引用計(jì)數(shù)降到0時(shí)宏邮,該僵尸實(shí)現(xiàn)會將該對象轉(zhuǎn)換成僵尸對象。僵尸對象的作用是在你向它發(fā)送消息時(shí)眶根,它會顯示一段日志并自動跳入調(diào)試器蜀铲。
所以,當(dāng)在應(yīng)用中啟用NSZombie而不是讓應(yīng)用直接崩潰時(shí)属百,一個(gè)錯(cuò)誤的內(nèi)存訪問就會變成一條無法識別的消息發(fā)送給僵尸對象记劝。僵尸對象會顯示接收到的消息,然后跳入調(diào)試器族扰,這樣你就可以查看到底哪時(shí)出了問題厌丑。 可以在Xcode的scheme頁面中設(shè)置NSZombieEnabled環(huán)境變量。點(diǎn)擊Product-Edit Scheme打開該頁面渔呵,然后勾選Enable Zombie Objects復(fù)選框怒竿,如圖所示:
僵尸在RAC出現(xiàn)以前作用很大。但自從有了ARC扩氢,如果你在對象的所有權(quán)方面比較注意耕驰,那么通常不會碰到內(nèi)存相關(guān)的崩潰。
二录豺、SIGSEGV
段錯(cuò)誤信息(SIGSEGV)是操作系統(tǒng)產(chǎn)生的一個(gè)更嚴(yán)重的問題朦肘。當(dāng)硬件出現(xiàn)錯(cuò)誤、訪問不可讀的內(nèi)存地址或向受保護(hù)的內(nèi)存地址寫入數(shù)據(jù)時(shí)双饥,就會發(fā)生這個(gè)錯(cuò)誤媒抠。
硬件錯(cuò)誤這一情況并不常見。當(dāng)要讀取保存在RAM中的數(shù)據(jù)咏花,而該位置的RAM硬件有問題時(shí)趴生,你會收到SIGSEGV。SIGSEGV更多是出現(xiàn)在后兩種情況昏翰。默認(rèn)情況下苍匆,代碼頁不允許進(jìn)行寫操作。當(dāng)應(yīng)用中的某個(gè)指針指向代碼頁并試圖修改指向位置的值時(shí)棚菊,你會收到SIGSEGV浸踩。當(dāng)要讀取一個(gè)指針的值,而它被初始化成指向無效內(nèi)存地址的垃圾值時(shí)窍株,你也會收到SIGSEGV民轴。
SIGSEGV錯(cuò)誤調(diào)試起來更困難攻柠,而導(dǎo)致SIGSEGV的最常見原因是不正確的類型轉(zhuǎn)換。要避免過度使用指針或嘗試手動修改指針來讀取私有數(shù)據(jù)結(jié)構(gòu)后裸。如果你那樣做了瑰钮,而在修改指針時(shí)沒有注意內(nèi)存對齊和填充問題,就會收到SIGSEGV微驶。
三浪谴、SIGBUS
總線錯(cuò)誤信號(SIGBUG)代表無效內(nèi)存訪問,即訪問的內(nèi)存是一個(gè)無效的內(nèi)存地址因苹。也就是說苟耻,那個(gè)地址指向的位置根本不是物理內(nèi)存地址(它可能是某個(gè)硬件芯片的地址)。
四扶檐、SIGTRAP
SIGTRAP代表陷阱信號凶杖。它并不是一個(gè)真正的崩潰信號。它會在處理器執(zhí)行trap指令發(fā)送款筑。LLDB調(diào)試器通常會處理此信號智蝠,并在指定的斷點(diǎn)處停止運(yùn)行。如果你收到了原因不明的SIGTRAP奈梳,先清除上次的輸出杈湾,然后重新進(jìn)行構(gòu)建通常能解決這個(gè)問題。
五攘须、EXC_ARITHETIC
當(dāng)要除零時(shí)漆撞,應(yīng)用會收到EXC_ARITHMETIC信號。這個(gè)錯(cuò)誤應(yīng)該很容易解決于宙。
六浮驳、SIGILL
SIGILL代表signal illegal instruction(非法指令信號)。當(dāng)在處理器上執(zhí)行非法指令時(shí)限煞,它就會發(fā)生抹恳。執(zhí)行非法指令是指员凝,將函數(shù)指針會給另外一個(gè)函數(shù)時(shí)署驻,該函數(shù)指針由于某種原因是壞的,指向了一段已經(jīng)釋放的內(nèi)存或是一個(gè)數(shù)據(jù)段健霹。有時(shí)你收到的是EXC_BAD_INSTRUCTION而不是SIGILL旺上,雖然它們是一回事,不過EXC_*等同于此信號不依賴體系結(jié)構(gòu)糖埋。
七宣吱、SIGABRT
SIGABRT代表SIGNAL ABORT(中止信號)。當(dāng)操作系統(tǒng)發(fā)現(xiàn)不安全的情況時(shí)瞳别,它能夠?qū)@種情況進(jìn)行更多的控制征候;必要的話杭攻,它能要求進(jìn)程進(jìn)行清理工作。在調(diào)試造成此信號的底層錯(cuò)誤時(shí)疤坝,并沒有什么妙招兆解。Cocos2d或UIKit等框架通常會在特定的前提條件沒有滿足或一些糟糕的情況出現(xiàn)時(shí)調(diào)用C函數(shù)abort(由它來發(fā)送此信號)。當(dāng)SIGABRT出現(xiàn)時(shí)跑揉,控制臺通常會輸出大量的信息锅睛,說明具體哪里出錯(cuò)了。由于它是可控制的崩潰历谍,所以可以在LLDB控制臺上鍵入bt命令打印出回溯信息现拒。
八、看門狗超時(shí)
這種崩潰通常比較容易分辨望侈,因?yàn)殄e(cuò)誤碼是固定的0x8badf00d印蔬。在iOS上,它經(jīng)常出現(xiàn)在執(zhí)行一個(gè)同步網(wǎng)絡(luò)調(diào)用而阻塞主線程的情況脱衙。因此扛点,永遠(yuǎn)不要進(jìn)行同步網(wǎng)絡(luò)調(diào)用。