iOS實錄14:淺談iOS Crash(一)

[這是第14篇]

序: iOS Crash問題是iOS開發(fā)中難以忽視的存在舆驶,本文就捕獲iOS Crash捣炬、Crash日志組成溶弟、Crash日志符號化異常信息解讀蒲稳、常見的Crash五部分介紹氮趋。

一伍派、捕獲iOS Crash

1、設(shè)置異常斷點并運行
設(shè)置異常斷點.png

說明:設(shè)置Xcode異常斷點后運行程序剩胁,發(fā)生Crash時诉植,斷點會定位到出錯的代碼行,但僅適用于開發(fā)階段昵观。線上APP的Crash還需要通過收集Crash機制來捕獲Crash并記錄在日志中晾腔。

2、Mach異常 索昂、Unix Signal 和 NSException

1) Mach異常是最底層的內(nèi)核級異常载庭,如EXC_BAD_ACCESS(內(nèi)存訪問異常)契耿,可以參考 Mach的exception_types定義

2) Unix Signal是Unix系統(tǒng)中的一種異步通知機制,Mach異常在host層被ux_exception轉(zhuǎn)換為相應(yīng)的Unix Signal劝贸,并通過threadsignal將信號投遞到出錯的線程潮罪。如SIGABRT(程序中止命令中止信號)康谆、 SIGALRM(程序超時信號),具體信號枚舉在iOS的sys/signal.h文件中嫉到。 它們可以利用Unix標(biāo)準(zhǔn)的signal機制來處理沃暗。

3) NSException是OC層,由iOS庫或者各種第三方庫或Runtime驗證出錯誤而拋出的異常何恶。如NSRangeException(數(shù)組越界異常)孽锥,它們可以被try catch捕獲(蘋果不建議用),如果未被捕獲或被@throw拋出细层,可以通過注冊NSSetUncaughtExceptionHandler函數(shù)來捕獲處理惜辑。

4) 當(dāng)錯誤發(fā)生時候,先在最底層產(chǎn)生Mach異常疫赎;Mach異常在host層被轉(zhuǎn)換為相應(yīng)的Unix Signal; 在OC層如果有對應(yīng)的NSException(OC異常)盛撑,就轉(zhuǎn)換成OC異常,OC異撑醺悖可以在OC層得到處理抵卫;如果OC異常一直得不到處理,程序會強行發(fā)送SIGABRT信號中斷程序胎撇。在OC層如果沒有對應(yīng)的NSException介粘,就只能讓Unix標(biāo)準(zhǔn)的signal機制來處理了。

5) 在捕獲Crash事件時晚树,優(yōu)選Mach異常姻采。因為Mach異常處理會先于Unix信號處理發(fā)生,如果Mach異常的handler讓程序exit了题涨,那么Unix信號就永遠(yuǎn)不會到達(dá)這個進(jìn)程了偎谁。而轉(zhuǎn)換Unix信號是為了兼容更為流行的POSIX標(biāo)準(zhǔn)(SUS規(guī)范)总滩,這樣就不必了解Mach內(nèi)核也可以通過Unix信號的方式來兼容開發(fā)。

6) 在方案實現(xiàn)時巡雨,通過捕獲Mach異常+Unix信號組合方式來捕獲Crash事件闰渔。在選擇具體方案時,可以選擇PLCrashReporter這樣優(yōu)秀的開源項目铐望,也可以選擇友盟冈涧、Bugly 這類完善的Crash上報和統(tǒng)計的產(chǎn)品(試項目需求而定)。

3正蛙、捕獲Crash

NSException是OC層的異常督弓。 在OC中雖然可以通過try catch捕獲NSException,阻止其繼續(xù)往外拋而導(dǎo)致Crash乒验,但是蘋果不建議這么做愚隧。不使用try catch,就意味著放棄捕獲OC層的異常锻全。最后只能注冊NSSetUncaughtExceptionHandler這個函數(shù)來捕獲狂塘,記錄異常信息,幫助解決問題鳄厌。

1) OC層中未被捕獲的異常荞胡,通過注冊NSUncaughtExceptionHandler捕獲異常信息

//注冊異常處理函數(shù)
NSSetUncaughtExceptionHandler(&uncaught_exception_handler);
//異常處理函數(shù)
static void uncaught_exception_handler (NSException *exception) {
  //可以取到 NSException 信息
  //...
  abort();
}

2) OC中層不能轉(zhuǎn)換的Mach異常,利用Unix標(biāo)準(zhǔn)的signal機制了嚎,注冊SIGABRT, SIGBUS, SIGSEGV等信號發(fā)生時的處理函數(shù)泪漂。

//注冊處理SIGSEGV信號
signal(SIGSEGV,handleSignal); 
// 注冊處理其他信號 ....

//信號處理函數(shù)
static void handleSignal( int sig ) {

}

二、Crash日志組成

上部分介紹了Crash的捕獲歪泳,這部分來看看Crash日志的組成萝勤。

1、日志內(nèi)容Demo#####

日志主要分為六個部分:進(jìn)程信息夹囚、基本信息纵刘、異常信息線程回溯荸哟、線程狀態(tài)二進(jìn)制映像假哎。下面是從某APP具體的Crash日志抽出的主要信息,展示如下:

//1鞍历、進(jìn)程信息
Hardware Model: iPhone9,2
Process: AppName [3580]
Path: /var/containers/Bundle/Application/C7B90C8A-E269-4413-A011-552971D1ED39/AppName.app
Identifier: xxxx.xxx.xxxx.xxx
Version: xx.xx
Code Type: ARM-64 (Native)
Parent Process:  [1]

//2舵抹、基本信息
Date/Time: 2017-05-22 03:05:06.743 +0800
OS Version: iPhone OS 10.2.1 (14D27)

//3、異常信息
Exception Type: NSInvalidArgumentException(SIGABRT)
Exception Codes: -[NSNull integerValue]: unrecognized selector sent to instance 0x1a9d88ef8 at 0x00000001835c7014
Crashed Thread: 0

//4劣砍、線程回溯 (展示發(fā)生Crash線程的回溯信息惧蛹,其他略)
Thread 0 Crashed: 
0  libsystem_kernel.dylib         0x00000001835c7014 __pthread_kill + 4
1  libsystem_c.dylib              0x000000018353b400 abort + 140
2  AppName                         0x0000000100a26704 0x0000000100028000 + 10479360
3  CoreFoundation                 0x00000001845f9538 ___handleUncaughtException +  644
2  CoreFoundation                 0x0000000184600268 ___methodDescriptionForSelector
3  CoreFoundation                 0x00000001845fd270 ____forwarding___ +  916
4  CoreFoundation                 0x00000001844f680c _CF_forwarding_prep_0 + 80
5  AppName                         0x0000000100205280 0x0000000100028000 + 1954432
6  AppName                         0x00000001002ae59c 0x0000000100028000 + 2647440
7  AppName                         0x0000000100482944 0x0000000100028000 + 4565312
16 CoreFoundation                 0x00000001845a6810 ___CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ +  12
     +  12
17 CoreFoundation                 0x00000001845a43fc ___CFRunLoopRun +  1660
18 CoreFoundation                 0x00000001844d22b8 CFRunLoopRunSpecific + 436

//5、進(jìn)程狀態(tài)(展示部分)
Thread 0 crashed with ARM 64 Thread State:
     x0:  000000000000000000    x1: 000000000000000000    x2: 000000000000000000     x3: 0xffffffffffffffff
     x4:  0x0000000000000010    x5: 0x0000000000000020    x6: 000000000000000000     x7: 000000000000000000
     x8:  0x0000000008000000    x9: 0x0000000004000000   x10: 000000000000000000    x11: 0x00000001ac336c83
    x12: 0x00000001ac336c83    x13: 0x0000000000000018   x14: 0x0000000000000001    x15: 0x0000000000000881
    x16: 0x0000000000000148    x17: 000000000000000000   x18: 000000000000000000    x19: 0x0000000000000006

//6、二進(jìn)制映像 (展示部分)
Binary Images:
0x100028000 - 0x1011dbfff +AppName arm64 <ff7a4009322b386ea3e8e9a3fde05be4> /var/containers/Bundle/Application/C7B90C8A-E269-4413-A011-552971D1ED39/AppName.app/AppName
0x18368a000 - 0x183693fff  libsystem_pthread.dylib arm64 <258dc0c51499393bba7ba3e83dc5bfbb> /usr/lib/system/libsystem_pthread.dylib
0x1835a8000 - 0x1835ccfff  libsystem_kernel.dylib arm64 <1baa3f5629c43467879d4cf463a20b06> /usr/lib/system/libsystem_kernel.dylib
0x1834b1000 - 0x1834b5fff  libdyld.dylib arm64 <db54f120486a3710a684ce8bb1cb9d71> /usr/lib/system/libdyld.dylib
0x1834d8000 - 0x183556fff  libsystem_c.dylib arm64 <8a5a190d70563f3c8d4ce16cab74f599> /usr/lib/system/libsystem_c.dylib
0x183481000 - 0x1834b0fff  libdispatch.dylib arm64 <fb1d0baf642337d1bea0af309586df97> /usr/lib/system/libdispatch.dylib
0x183028000 - 0x183401fff  libobjc.A.dylib arm64 <538f809dcd7c35ceb59d99802248f045> /usr/lib/libobjc.A.dylib
2香嗓、日志內(nèi)容組成分析#####

整個日志內(nèi)容中迅腔,直接和Crash信息相關(guān),最能幫助開發(fā)者定位問題部分是: 異常信息線程回溯部分的內(nèi)容靠娱。

1) 進(jìn)程信息:發(fā)生Crash閃退進(jìn)程的相關(guān)信息

  • Hardware Model : 標(biāo)識設(shè)備類型沧烈。 如果很多崩潰日志都是來自相同的設(shè)備類型,說明應(yīng)用只在某特定類型的設(shè)備上有問題像云。上面的日志里锌雀,崩潰日志產(chǎn)生的設(shè)備是iPhone 7 Plus (iPhone 7 Plus 也是2個版本 iPhone9,2 和 iPhone9,4. 硬件代號為 D11AP 和 D111AP. 型號有: A1661, A1784, A1785 和 A1786. )

  • Process 是應(yīng)用名稱。中括號里面的數(shù)字是閃退時應(yīng)用的進(jìn)程ID迅诬。

2) 基本信息:給出了一些基本信息腋逆,包括閃退發(fā)生的日期和時間,設(shè)備的iOS版本侈贷。

3) 異常信息:閃退發(fā)生時拋出的異常類型惩歉。還能看到異常編碼和拋出異常的線程。

//以上面內(nèi)容中的異常信息為例:
Exception Type: NSInvalidArgumentException(SIGABRT)
Exception Codes: -[NSNull integerValue]: unrecognized selector sent to instance 0x1a9d88ef8 at 0x00000001835c7014
Crashed Thread: 0
  • Exception Type異常類型:通常包含1.7中的Signal信號和EXC_BAD_ACCESS铐维,NSRangeException等柬泽。
  • Exception Codes:異常編碼:
  • Crashed Thread:發(fā)生Crash的線程id

4) 線程回溯:回溯是閃退發(fā)生時所有活動幀清單。它包含閃退發(fā)生時調(diào)用函數(shù)的清單嫁蛇。

5) 線程狀態(tài):閃退時寄存器中的值。一般不需要這部分的信息露该,因為回溯部分的信息已經(jīng)足夠讓你找出問題所在睬棚。

6) 二進(jìn)制映像:閃退時已經(jīng)加載的二進(jìn)制文件。

三解幼、異常信息解讀####

1抑党、Exception Type(異常類型)#####
  • Exception Type:通常包含Signal信號 和 EXC_BAD_ACCESS,NSRangeException等撵摆。

|異常類型 | 可能的原因| 調(diào)試方法|
|--|--|
| EXC_CRASH | unrecognized selector | All Exception Point |
| EXC_BAD_ACCESS| 內(nèi)存訪問錯誤 | NSZombie|
| SIGSEGV | 引用了released對象 / 引用未init的對象 / 數(shù)組越界/ 試圖往沒有寫權(quán)限的內(nèi)存地址寫數(shù)據(jù) |NSZombie|
| SIGABRT| 邏輯錯誤導(dǎo)致的Crash,比如嘗試多次釋放同一個沒存| 邏輯檢查 |
| SIGPIPE | TCP突然斷開底靠,再發(fā)送數(shù)據(jù)| 添加signal(SIGPIPE,XX)|

具體信號說明參見iOS異常捕獲

2特铝、Exception Code(異常編碼)#####
  • Exception Code:以一些文字開頭暑中,緊接著是一個或多個十六進(jìn)制值。這些數(shù)值說明了Crash發(fā)生的本質(zhì)鲫剿。

  • 從Exception Code中鳄逾,可以區(qū)分出Crash是因為程序錯誤、非法內(nèi)存訪問還是其他原因灵莲。常見的異常編碼如下表:

異常編碼 描述
0x8badf00d ate bad food 雕凹,表示應(yīng)用是因為發(fā)生watchdog超時而被iOS終止的。通常是應(yīng)用花費太多時間而無法啟動、終止或響應(yīng)用系統(tǒng)事件枚抵。
0xdeadfa11 dead fall线欲,用戶強制退出。
0xbaaaaaad 用戶按住Home鍵和音量鍵汽摹,獲取當(dāng)前內(nèi)存狀態(tài)李丰,不代表崩潰。
0xbad22222 VoIP 應(yīng)用因為過于頻繁重啟而被終止
0xc00010ff cool off竖慧,因為太燙了被干掉
0xdead10cc dead lock嫌套,表明應(yīng)用因為在后臺運行時占用系統(tǒng)資源(如通訊錄數(shù)據(jù)庫)
0xbbadbeef bad beef,發(fā)生致命錯誤

說明1:詳細(xì)的異常編碼代表的含義請參考:Hexspeak

說明2:在后臺任務(wù)列表中關(guān)閉已掛起的應(yīng)用不會產(chǎn)生崩潰日志圾旨。 因為應(yīng)用一旦被掛起踱讨,它何時被終止都是合理的。所以不會產(chǎn)生崩潰日志砍的。

四痹筛、Crash日志符號化

1、概述#####

線程回溯部分內(nèi)容如下:

5  AppName                         0x0000000100205280 0x0000000100028000 + 1954432
6  AppName                         0x00000001002ae59c 0x0000000100028000 + 2647440

這兩條記錄包括四列:(以第一條記錄為例子)

  • 幀編號—— 5(數(shù)字越小廓鞠,發(fā)生時間越晚帚稠,發(fā)生順序越往后,越好鎖定問題的范圍)
  • 二進(jìn)制庫的名稱 ——此處是 AppName.
  • 調(diào)用方法的地址 ——此處是 0x0000000100205280.
  • 第四列分為兩個子列床佳,一個基本地址和一個偏移量滋早。此處是 x0000000100028000 + 1954432, 第一個數(shù)字指向文件,第二個數(shù)字指向文件中的代碼行砌们。

說明1:線程回溯部分并不是我們習(xí)慣使用方法名和行數(shù)杆麸,而是十六進(jìn)制地址。所以我們在分析Crash前需要將這些十六進(jìn)制地址轉(zhuǎn)化成方法名稱和行數(shù)浪感,改過程被稱為符號化昔头。

說明2:符號化Crash日志需要獲取對應(yīng)的應(yīng)用二進(jìn)制文件以及生成二進(jìn)制文件時產(chǎn)生的 .dSYM 文件(符號表)。必需完全匹配才行影兽。否則揭斧,日志將無法被完全符號化。

說明3: Xcode編譯項目后峻堰,會得到同名的 dSYM 文件(符號表)讹开,dSYM 文件(符號表)是保存 16 進(jìn)制函數(shù)地址映射信息的中轉(zhuǎn)文件,我們調(diào)試的 symbols 都會包含在這個文件中茧妒,并且每次編譯項目的時候都會生成一個新的 dSYM 文件萧吠,位于 /Users/<用戶名>/Library/Developer/Xcode/Archives 目錄下,對于每一個發(fā)布版本我們都很有必要保存對應(yīng)的 Archives 文件桐筏。

說明4:符號化可以使用Xcode的兩種命令 symbolicatecrash命令 + ** atos命令 **

2纸型、symbolicatecrash命令#####

1)首選找到symbolicatecrash命令的位置

  find /Applications -name symbolicatecrash -type f  
  //我的本機命令的位置:/Applications/Xcode.app/Contents/SharedFrameworks/DVTFoundation.framework/Versions/A/Resources/symbolicatecrash

2)找到線上版本對應(yīng)的xcarchive文件。從中找到.dSYM和.app文件

xcarchive所在的路徑一般在: /Users/<用戶名>/Library/Developer/Xcode/Archives 目錄下

3)獲取crash日志文件

  • 線上App的Crash日志經(jīng)由Crash日志收集服務(wù)獲得(主要來源)。

  • 也可以從真機上獲取Crash日志文件狰腌。點擊Window -> Devices除破,選擇你自己的機器,然后點擊View Device Logs琼腔,右鍵可以導(dǎo)出Crash文件瑰枫。

  • 獲取的這些日志文件都需要符號化處理。

4)將symbolicatecrash丹莲、.dSYM光坝、.app、crash.crash拷貝到桌面下同一個文件夾下

5)檢查 xx.app 和 xx.app.dSYM 文件以及crash 文件這三種的 UUID是否一致甥材。

  • 查看 xx.app 文件的 UUID盯另,terminal 中輸入命令 :

    dwarfdump --uuid xx.app/xx (xx代表你的項目名)
    
  • 查看 xx.app.dSYM 文件的 UUID ,在 terminal 中輸入命令:

    dwarfdump --uuid xx.app.dSYM 
    
  • 查看crash 日志中的Incident Identifier (crash 文件的 UUID)

6)使用命令洲赵,生成“可定位問題的crash文件”

//symbolreportXXX.crash就是符號化后的文件
./symbolicatecrash crashXXX.crash appName.app.dSYM > symbolreportXXX.crash 

7) 根據(jù)符號化后的線程回溯信息鸳惯,可以幫助定位出問題的代碼行。

說明:如果執(zhí)行symbolicatecrash命令出現(xiàn) Error: "DEVELOPER_DIR" is not defined at ./symbolicatecrash...這樣的錯誤叠萍,可以在執(zhí)行命令前芝发,輸入export DEVELOPER_DIR="/Applications/XCode.app/Contents/Developer"

3、atos命令#####

在符號化時候苛谷,還可以使用atos命令辅鲸。發(fā)現(xiàn)armv7處理器上的crash使用symbolicatecrash無法符號化。

1)將.dSYM腹殿、.app瓢湃、crash.crash放到同一個文件夾下。

2) 知道crash文件的UUID:執(zhí)行g(shù)rep "AppName arm" *crash赫蛇,得到結(jié)果

crash1.crash:0x100040000 - 0x100e23fff +AppName arm64 <ba0e190dcd1b37349e1362be7e9b7e62> /var/containers/Bundle/Application/55A4D641-847F-4D24-86E1-129B28461858/AppName.app/AppName
crash2.crash:0x100060000 - 0x100e43fff +AppName arm64 <ba0e190dcd1b37349e1362be7e9b7e62> /var/containers/Bundle/Application/3229ED68-8D19-406D-A3F5-EC0310C9DB7C/QAppName.app/AppName
crash3.crash:    0x5000 -   0xce8fff +AppName armv7 <7d62327effef37d384658020625a9944> /var/containers/Bundle/Application/C6BE271D-2EAC-42C0-8E72-4523F88C76B2/AppName.app/AppName

其中0x100040000、0x100060000雾叭、0x5000是加載地址(loadingAddress), 而arm64悟耘、armv7 是 architecture 的值(architectureValue),這兩個值后面都要用织狐。

3)然后執(zhí)行atos命令,輸入成功暂幼,進(jìn)入待輸入狀態(tài)

xcrun atos -o appName.app.dSYM/Contents/Resources/DWARF/appName -l loadingAddress -arch architectureValue

4) 此時輸入App對應(yīng)的Crash地址,得到發(fā)生crash的信息移迫。

實例1

    grep "AppName arm" *crash
    xcrun atos -o AppName.app.dSYM/Contents/Resources/DWARF/AppName -l 0x100040000 -arch arm64

實例2

    grep "AppName arm" *crash
    xcrun atos -o AppName.app.dSYM/Contents/Resources/DWARF/AppName -l 0x5000 -arch armv7

五旺嬉、常見的Crash####

有一些Crash比較常見,下面羅列出5種常見的Crash厨埋。

1邪媳、數(shù)組操作
  • 場景1:取數(shù)據(jù)索引越界。一般發(fā)生在UITableView的使用中,因為cellForRowAtIndexPath代理方法是異步執(zhí)行的雨效,UITableView對象的dataSource一旦在加載數(shù)據(jù)過程中發(fā)生變化迅涮,極有可能發(fā)生數(shù)組越界的異常。在多線程場景下徽龟,列表界面的數(shù)據(jù)有可能經(jīng)常變化叮姑,很可能發(fā)生;當(dāng)列表界面數(shù)據(jù)不怎么變化的時候据悔,幾乎感知不到這種異常的存在传透。

解決辦法:從數(shù)組中取數(shù)據(jù)前,校驗索引是否正確极颓。

    @implementation NSMutableArray (Safe)

    - (id)safeObjectAtIndex:(NSUInteger)index{

        if (index < self.count){
            return [self objectAtIndex:index];
        }else{
            NSLog(@"警告:數(shù)組越界!!!");
        }    
        return nil;
    }

    @end
  • 場景2:數(shù)組添加數(shù)據(jù)對象時nil

解決辦法:添加對象到數(shù)組前朱盐,判斷是否是nil

說明:數(shù)組的刪除等操作處理類似,數(shù)組操作前要進(jìn)行數(shù)據(jù)校驗讼昆。

2托享、多線程下的Crash#####
  • 一般多線程發(fā)生的Crash,會收到SIGSEGV信號浸赫,表明試圖訪問未分配給自己的內(nèi)存, 或試圖往沒有寫權(quán)限的內(nèi)存地址寫數(shù)據(jù)闰围。

  • 場景1:子線程中更新UI

解決辦法:將UI更新操作放在主線程中,可以使用performSelectorOnMainThread 或 GCD

    //子線程中既峡,使用宏將更新UI的任務(wù)派發(fā)到主隊列
    #define dispatch_main_sync_safe(block) \
    if ([NSThread isMainThread]) { \
       block(); \
    } else { \
        dispatch_sync(dispatch_get_main_queue(), block); \
    }

    #define dispatch_async_main(block)              dispatch_async(dispatch_get_main_queue(), block)
  • 場景2:多線程中創(chuàng)建單例

    解決辦法:使用dispatch_once羡榴,保證代碼只執(zhí)行一次,保證線程安全运敢。

      //以QSAccountManager單例為例
      static QSAccountManager *_shareManager = nil;
      + (instancetype)shareManager{
    
          static dispatch_once_t once;
          dispatch_once(&once, ^{
              _shareManager = [[self alloc] init];
          });
          return _shareManager;
      }
    
      + (instancetype)allocWithZone:(struct _NSZone *)zone{
    
          static dispatch_once_t onceToken;
          dispatch_once(&onceToken, ^{
              _shareManager = [super allocWithZone:zone];
          });
          return _shareManager;
      }
    
     - (nonnull id)copyWithZone:(nullable NSZone *)zone{
          return _shareManager;
      }
    
  • 場景3:多線程下非線程安全類的使用校仑,如NSMutableArray、NSMutableDictionary

    解決辦法:使用派發(fā)隊列或鎖保證數(shù)據(jù)讀寫安全传惠。具體實現(xiàn)詳見 iOS實錄12:NSMutableArray使用中忽視的問題中第一部分迄沫。

  • 場景4:數(shù)據(jù)緩存到磁盤和讀取。

    解決辦法:使用派發(fā)隊列或鎖保證數(shù)據(jù)讀寫安全卦方。如將數(shù)據(jù)的讀取和寫異步放入串行同步隊列羊瘩,保證數(shù)據(jù)同步,線程安全盼砍。

3尘吗、WatchDog 超時造成的Crash
  • 一般異常編碼是0x8badf00d ,表示應(yīng)用是因為發(fā)生watchdog超時而被iOS終止的浇坐。通常是應(yīng)用花費太多時間而無法啟動睬捶、終止或響應(yīng)用系統(tǒng)事件。

  • 場景1:主線程中執(zhí)行耗時的操作近刘,導(dǎo)致主線程被卡超過一定的時間擒贸。

    解決辦法:主線程中只負(fù)責(zé)UI的更新和響應(yīng)臀晃,將耗時的操作采用異步的方式放到后臺線程執(zhí)行。耗時操作包括:網(wǎng)絡(luò)請求酗宋,數(shù)據(jù)庫讀寫等积仗。

4、performSelector:withObject:afterDelay下的Crash
  • 場景1:對象釋放比performSelector:afterDelay要早

    解決辦法:在對應(yīng)類的dealloc中執(zhí)行cancelPreviousPerformRequestsWithTarget取消執(zhí)行蜕猫。

5寂曹、SIGPIPE導(dǎo)致的程序退出
  • 當(dāng)服務(wù)器close一個連接時,若client端接著發(fā)數(shù)據(jù)回右。根據(jù)TCP協(xié)議的規(guī)定隆圆,會收到一個RST響應(yīng),client再往這個服務(wù)器發(fā)送數(shù)據(jù)時翔烁,系統(tǒng)會發(fā)出一個SIGPIPE信號給進(jìn)程渺氧,告訴進(jìn)程這個連接已經(jīng)斷開了,不要再寫了蹬屹。而根據(jù)信號的默認(rèn)處理規(guī)則侣背,SIGPIPE信號的默認(rèn)執(zhí)行動作是terminate(終止、退出),所以client會退出慨默。

  • 場景:長連接socket或重定向管道進(jìn)入后臺贩耐,沒有關(guān)閉

    解決辦法1:切換到后臺時,關(guān)閉長連接和管道厦取,回到前臺再重建潮太;

    解決辦法2:使用signal(SIGPIPE,SIG_IGN),將SIGPIPE交給了系統(tǒng)處理虾攻。這么做將SIGPIPE設(shè)為SIG_IGN铡买,使得客戶端不執(zhí)行默認(rèn)動作,即不退出霎箍。

End

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市樊拓,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌塘慕,老刑警劉巖筋夏,帶你破解...
    沈念sama閱讀 207,248評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異图呢,居然都是意外死亡条篷,警方通過查閱死者的電腦和手機骗随,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,681評論 2 381
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來赴叹,“玉大人鸿染,你說我怎么就攤上這事∑蚯桑” “怎么了涨椒?”我有些...
    開封第一講書人閱讀 153,443評論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長绽媒。 經(jīng)常有香客問我蚕冬,道長,這世上最難降的妖魔是什么是辕? 我笑而不...
    開封第一講書人閱讀 55,475評論 1 279
  • 正文 為了忘掉前任囤热,我火速辦了婚禮,結(jié)果婚禮上获三,老公的妹妹穿的比我還像新娘旁蔼。我一直安慰自己,他們只是感情好疙教,可當(dāng)我...
    茶點故事閱讀 64,458評論 5 374
  • 文/花漫 我一把揭開白布棺聊。 她就那樣靜靜地躺著,像睡著了一般松逊。 火紅的嫁衣襯著肌膚如雪躺屁。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,185評論 1 284
  • 那天经宏,我揣著相機與錄音犀暑,去河邊找鬼。 笑死烁兰,一個胖子當(dāng)著我的面吹牛耐亏,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播沪斟,決...
    沈念sama閱讀 38,451評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼广辰,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了主之?” 一聲冷哼從身側(cè)響起择吊,我...
    開封第一講書人閱讀 37,112評論 0 261
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎槽奕,沒想到半個月后几睛,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,609評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡粤攒,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,083評論 2 325
  • 正文 我和宋清朗相戀三年所森,在試婚紗的時候發(fā)現(xiàn)自己被綠了囱持。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,163評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡焕济,死狀恐怖纷妆,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情晴弃,我是刑警寧澤掩幢,帶...
    沈念sama閱讀 33,803評論 4 323
  • 正文 年R本政府宣布,位于F島的核電站肝匆,受9級特大地震影響粒蜈,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜旗国,卻給世界環(huán)境...
    茶點故事閱讀 39,357評論 3 307
  • 文/蒙蒙 一枯怖、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧能曾,春花似錦度硝、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,357評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至驼唱,卻和暖如春藻茂,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背玫恳。 一陣腳步聲響...
    開封第一講書人閱讀 31,590評論 1 261
  • 我被黑心中介騙來泰國打工辨赐, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人京办。 一個月前我還...
    沈念sama閱讀 45,636評論 2 355
  • 正文 我出身青樓掀序,卻偏偏與公主長得像,于是被迫代替她去往敵國和親惭婿。 傳聞我的和親對象是個殘疾皇子不恭,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,925評論 2 344

推薦閱讀更多精彩內(nèi)容

  • 本文就捕獲iOS Crash、Crash日志組成财饥、Crash日志符號化换吧、異常信息解讀、常見的Crash五部分介紹钥星。...
    xukuangbo_閱讀 1,571評論 0 0
  • 本文整理下最近對于crash采集的總結(jié)式散,和踩過的坑。 CrashReporter 首先打颤,iOS有自己的CrashR...
    談Xx閱讀 19,741評論 15 66
  • 比較好的轉(zhuǎn)載:http://www.cocoachina.com/ios/20151218/14748.html轉(zhuǎn)...
    liudhkk閱讀 929評論 0 2
  • 第一次數(shù)星星是在奶奶的懷里暴拄,一顆,兩顆编饺,三顆…在奶奶哼的搖籃曲里數(shù)著星星沉沉地睡去乖篷。童年時,在晚上透且,奶奶總喜歡帶我...
    逮逮愛旅行閱讀 602評論 0 0
  • 霧霾的危害…… 介個就不用小編在介紹了吧撕蔼? 據(jù)說是多少年后肺癌會井噴似的出現(xiàn)……因為霧霾里面的顆粒物讓人的免疫力下...
    九九朝顏閱讀 575評論 0 2