問(wèn)題描述
近來(lái),發(fā)現(xiàn)Xcode的模擬器越來(lái)越不靠不住了,應(yīng)用開(kāi)發(fā)完,在模擬器上面各種流暢各種運(yùn)行得飛起,但是安裝到真機(jī)之后,就崩潰了,是閃退啊!~~o(>_<)o ~~
在模擬器上面沒(méi)有問(wèn)題,但是裝到真機(jī)的時(shí)候,發(fā)現(xiàn)閃退,這樣比較難定位到原因。
辦法還是有的,問(wèn)題也總能解決的。
方法一:我們可能通過(guò)收集手機(jī)的日志,查看崩潰日志;
方法二:通過(guò)集成第三方的插件來(lái)追蹤bug(例如:騰訊的bugly、友盟),不過(guò)建議只用一家的,因?yàn)槎嗉业囊黄鹩?,可能?huì)有其他問(wèn)題;
方法三:真機(jī)調(diào)試。
為了迅速定位并解決問(wèn)題,最終還是選擇了方法三,并且最終解決了問(wèn)題。
1. 真機(jī)調(diào)試
從Xcode7之后,真機(jī)調(diào)試已經(jīng)是沒(méi)有任何門檻了,我們只需要注冊(cè)一個(gè)蘋果的開(kāi)發(fā)者賬號(hào)即可以無(wú)證書(shū)也可以真機(jī)調(diào)試,操作如下:
第一步、打開(kāi)Xcode 選擇屏幕左上角Xcode-> PReferencese

第二步:選擇Account 點(diǎn)擊左下角的+按鈕登陸Apple ID
第三步:登陸你的Apple ID
第四步:登陸成功之后,在右側(cè)會(huì)顯示小伙伴的賬號(hào)在iOS和Mac上都是free的,雙擊這一列(或者點(diǎn)擊選擇view details)
第五步:這里需要一定時(shí)間獲取你的Apple ID的開(kāi)發(fā)者信息,點(diǎn)擊iOS Development 后面的create ,然后稍等片刻,直到create按鈕不見(jiàn)了。

第六步:到了這里基本上已經(jīng)結(jié)束----開(kāi)始真機(jī)測(cè)試:打開(kāi)需要真機(jī)測(cè)試的項(xiàng)目插上手機(jī)(Xcode第一次鏈接手機(jī)會(huì)很慢,可以選擇Xcode菜單欄中的window->devices查看手機(jī)是否準(zhǔn)備就緒了),選擇項(xiàng)目文件-> General - > Team -> 選擇你屬于你的Apple ID ,再點(diǎn)擊Team 下面的fix issue修復(fù)Team 正下方的警告。
第七步:最后一個(gè)問(wèn)題,你最終會(huì)發(fā)現(xiàn)Xcode會(huì)彈出一個(gè)框(process launch failed: Security),這里需要打開(kāi)你手機(jī)的設(shè)置->通用- > 描述文件-> 選擇你的Apple ID - > 點(diǎn)擊信任
至此,真機(jī)調(diào)試的過(guò)程就搞好了,是不是比以前簡(jiǎn)單多了
2. 如何調(diào)試僵尸對(duì)象
經(jīng)過(guò)上面的真機(jī)調(diào)試之后,發(fā)現(xiàn)我們的程序崩在了一個(gè)方法里,并且報(bào)錯(cuò) “Thread 1:EXC_BAD_ACCESS(code=1,address=0x4000)”,這種錯(cuò)誤通常是內(nèi)存管理的問(wèn)題,一般是訪問(wèn)了已經(jīng)釋放的對(duì)象導(dǎo)致的,可以開(kāi)啟僵尸對(duì)象(Zombie Objects)來(lái)定位問(wèn)題。
第一步:還是打開(kāi)Xcode 選擇屏幕左上角Xcode-> PReferencese,不過(guò)我們這次是要設(shè)置一下輸出信息,調(diào)試的時(shí)候輸出更多的信息,如下截圖,勾上:

第二步:再對(duì)環(huán)境變量進(jìn)行設(shè)置:菜單Product > Scheme > Edit Scheme
把紅色圈里面的三個(gè)選項(xiàng)都勾上

開(kāi)啟該選項(xiàng)后,程序在運(yùn)行時(shí),如果訪問(wèn)了已經(jīng)釋放的對(duì)象,則會(huì)給出較準(zhǔn)確的定位信息,可以幫助確定問(wèn)題所在。
該功能的原理是,在對(duì)象釋放(retainCount為0)時(shí),使用一個(gè)內(nèi)置的Zombie對(duì)象,替代原來(lái)被釋放的對(duì)象。無(wú)論向該對(duì)象發(fā)送什么消息(函數(shù)調(diào)用),都會(huì)觸發(fā)異常,拋出調(diào)試信息。
記得在問(wèn)題被修復(fù)后,關(guān)閉該功能?。?/p>
第三步:設(shè)置好后調(diào)試程序,在輸出界面發(fā)現(xiàn)了-[CFString retain]: message sent to deallocated instance錯(cuò)誤日志
到這里,就已經(jīng)很明顯看出來(lái)是什么原因?qū)е鲁绦虮罎⒌牧?,然后再去分析代碼,靜下心來(lái)肯定能解決問(wèn)題的了。
我這里是因?yàn)橄蛞粋€(gè)空的NSString類型發(fā)送消息導(dǎo)致崩潰的,但是這個(gè)問(wèn)題只在iOS9版本崩潰,iOS10就沒(méi)問(wèn)題,這個(gè)還值得深究。
3. 例子
為了能夠更加詳細(xì)地說(shuō)明調(diào)試僵尸對(duì)象,并定位到崩潰的原因,下面列出一個(gè)簡(jiǎn)單的例子來(lái)說(shuō)明:
先創(chuàng)建一個(gè) DebugViewController,然后里面創(chuàng)建一個(gè)數(shù)組,然后釋放,在Controller將要出現(xiàn)的時(shí)候,向該數(shù)組發(fā)送一個(gè)消息:
<pre>#import "DebugViewController.h"
@interface DebugViewController ()
@end
@implementation DebugViewController
/*定義一個(gè)數(shù)組*/
static NSMutableArray*array;
-(void)viewDidLoad
{
[super viewDidLoad];
array= [[NSMutableArray alloc]initWithCapacity:5];
[array release];//釋放掉該數(shù)組
}
- (void)viewWillAppear:(BOOL)animated{
[array addObject:@"Hello"];//使用釋放掉的數(shù)組
}
@end
</pre>
在我們意料之中,程序崩潰了,報(bào)錯(cuò)信息如下:

我們用LLDB po我們的數(shù)組array對(duì)象,同樣沒(méi)有返回

打開(kāi)“活動(dòng)監(jiān)視器”,在進(jìn)程列表中找到測(cè)試APP對(duì)應(yīng)的進(jìn)程號(hào)PID(Xcode啟用調(diào)試后會(huì)在進(jìn)程列表中找到對(duì)應(yīng)APP的進(jìn)程)

從上面標(biāo)下劃線的地方,我們得到兩個(gè)主要的信息:
APP進(jìn)程ID:21122
崩潰地址:0x60008170cfd0
打開(kāi)“終端”,輸入以下命令:
sudo malloc_history 21122 0x60008170cfd0
得到錯(cuò)誤日志,這樣就能定位到最后調(diào)用的那行代碼

就是我們上面的release釋放掉了array對(duì)象導(dǎo)致的。