程式調試
● 調用堆棧
我們先寫一個 Demo 示範一下錯誤
- (void)viewDidLoad {
[super viewDidLoad];
[self testDemo];
}
- (void)testDemo {
NSString *str = nil;
NSArray *array = @[@"hello word!", str];
NSLog(@"%@", array);
}
運作後 程式很聽話的報錯了!
**2016-11-09 23:02:58.839 01-Bugly[976:81766] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[__NSPlaceholderArray initWithObjects:count:]: attempt to insert nil object from objects[1]'**
***** First throw call stack:**
**(**
** 0 CoreFoundation 0x000000011150034b __exceptionPreprocess + 171**
** 1 libobjc.A.dylib 0x0000000110f6121e objc_exception_throw + 48**
** 2 CoreFoundation 0x00000001114103b3 -[__NSPlaceholderArray initWithObjects:count:] + 275**
** 3 CoreFoundation 0x00000001114175c4 +[NSArray arrayWithObjects:count:] + 52**
** 4 01-Bugly 0x000000010fd06332 -[ViewController testDemo] + 98**
** 5 01-Bugly 0x000000010fd062c9 -[ViewController viewDidLoad] + 73**
** 6 UIKit 0x0000000111ac506d -[UIViewController loadViewIfRequired] + 1258**
** 7 UIKit 0x0000000111ac54a0 -[UIViewController view] + 27**
** 8 UIKit 0x000000011198f045 -[UIWindow addRootViewControllerViewIfPossible] + 71**
** 9 UIKit 0x000000011198f796 -[UIWindow _setHidden:forced:] + 293**
** 10 UIKit 0x00000001119a30a9 -[UIWindow makeKeyAndVisible] + 42**
** 11 UIKit 0x000000011191c259 -[UIApplication _callInitializationDelegatesForMainScene:transitionContext:] + 4818**
** 12 UIKit 0x00000001119223b9 -[UIApplication _runWithMainScene:transitionContext:completion:] + 1731**
** 13 UIKit 0x000000011191f539 -[UIApplication workspaceDidEndTransaction:] + 188**
** 14 FrontBoardServices 0x000000011482576b __FBSSERIALQUEUE_IS_CALLING_OUT_TO_A_BLOCK__ + 24**
** 15 FrontBoardServices 0x00000001148255e4 -[FBSSerialQueue _performNext] + 189**
** 16 FrontBoardServices 0x000000011482596d -[FBSSerialQueue _performNextFromRunLoopSource] + 45**
** 17 CoreFoundation 0x00000001114a5311 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 17**
** 18 CoreFoundation 0x000000011148a59c __CFRunLoopDoSources0 + 556**
** 19 CoreFoundation 0x0000000111489a86 __CFRunLoopRun + 918**
** 20 CoreFoundation 0x0000000111489494 CFRunLoopRunSpecific + 420**
** 21 UIKit 0x000000011191ddb6 -[UIApplication _run] + 434**
** 22 UIKit 0x0000000111923f34 UIApplicationMain + 159**
** 23 01-Bugly 0x000000010fd066cf main + 111**
** 24 libdyld.dylib 0x00000001132f868d start + 1**
** 25 ??? 0x0000000000000001 0x0 + 1**
**)**
**libc++abi.dylib: terminating with uncaught exception of type NSException**
**(lldb)**
我們來看一下錯誤資訊
通常程式崩潰後 我們的目光會聚焦在錯誤資訊的最上方部分 如下:
__NSPlaceholderArray **數組**
attempt to **試圖**
insert nil object **插入一個空對象**
from objects[1] **在索引[1]的位置**
通常看到這裡我們就開始想,程式到底哪錯了,到底在哪裡插入空對象了
然後就開始滿世界的去找,試想我們一個項目中有成百上千個檔案,我們這樣找要找到什麼時候
那我們如何找到更詳細的資訊呢?
在我們聚焦的錯誤資訊的下方就是程式錯誤的詳細資訊
它有一個專用名詞 調用堆棧
調用堆棧先執行的步驟在下方 後執行的步驟在上方
那調用堆棧給我們哪些詳細的資訊呢
10 UIKit 0x00000001119a30a9 -[UIWindow makeKeyAndVisible] +
** 程式啟動時調用的方法 **
5 01-Bugly 0x000000010fd062c9 -[ViewController viewDidLoad] + 73
** 我們剛剛在ViewController viewDidLoad 中調用了testDemo 方法 **
4 01-Bugly 0x000000010fd06332 -[ViewController testDemo] + 98
** 我們所調用的testDemo方法 在 ViewController 中**
3 CoreFoundation 0x00000001114175c4 +[NSArray arrayWithObjects:count:] + 52
** 嘗試給一個數組插入資料 **
再往後程式就崩潰了 我們通過上面的資訊就可以定位到 testDemo 這個函數出問題了
錯誤原因既是 我們向數組[1]中添加一個空對象
[__NSPlaceholderArray initWithObjects:count:]: attempt to insert nil object from objects[1]
發現這個線索之後 我們可以就直接去 ViewController 中 找到 testDemo 發現
NSString *str = nil;
為空
是以我們一定要學會調用堆棧的技巧 隻有善于使用這個技巧 我們才能更快的調試錯誤資訊
● 收集錯誤資訊
那我們在真機測試時同樣的錯誤提示的錯誤資訊是什麼呢?
如圖所示 在真機測試時隻顯示錯誤資訊,不顯示詳細的調用堆棧的内容
那程式上線後,我們如何收集錯誤資訊呢?
這時候我們就需要使用到第三方的架構 * Bugly *
**官方網站: https://bugly.qq.com/v2/
登入 QQ 後 如下圖
進入後我們注冊一下
注冊完成後 我們來內建 第三方架構 選中 SDK -> iOS SDK 使用指南
在這裡我推薦使用 CocoaPods 內建 Bugly 架構
打開Mac自帶終端
cd "項目根目錄"
pod init
建立 Podfile
将項目中 Podfile 拖入 Xcode 中
不要删除檔案中的内容
在 target 下方 粘貼 如下内容
pod 'Bugly'
回到終端中
pod install --no-repo-update
Tip: 我們可以通過 --help
找到 CocoaPods 的幫助資訊 這樣,需要的東西我們就可以直接複制粘貼~~
接下來我們回到項目中 這時候記得點 白色 的檔案
來到項目的 AppDelegate.m 中初始化 Bugly
//先導入頭檔案
#import <Bugly/Bugly.h>
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
//下面的内容一定要放在第一句 在程式啟動時 下面的代碼全部能監聽到!!!!
[Bugly startWithAppId:@"此處替換為你的AppId"];
return YES;
}
此處的 AppID 在我們剛剛注冊的 App 中 如下圖:
替換 AppID 後 我們導入架構的工作就完成了!
此時我們回到項目中運作程式 真機測試 繼續讓程式崩潰下~
崩潰後 稍等片刻回到 網站中檢視崩潰日志
這裡注意: 程式崩潰後 會在 AppDelegate.h 中打一個 斷點**
此時後面的程式就不會繼續執行 不執行就會導緻錯誤資訊無法送出到 Bugly 中
進而導緻我們在崩潰日志中 無法顯示崩潰結果
此時 我們回到手機中 點選執行個體程式 閃退即可**
點選進入 錯誤資訊
與我們在模拟器中 調用堆棧 的内容一緻 ,并且它還幫我們将錯誤資訊 标藍
末語:
當我們導入騰訊的第三方架構 Bugly 後
即便我們的程式上線了 我們也可以知道程式崩潰在哪裡!
即簡單 又友善