級別: ★☆☆☆☆
標籤:「Xcode控制檯調試」「iOS 調試臺」「iOS Console」
做者: Xs·H
審校: QiShare團隊php
在iOS項目開發過程當中,經常使用到靜態分析(Analyze)、斷點(Breakpoint)和控制檯(Console)進行代碼調試,其中控制檯調試最核心的的就是LLDB命令。本篇文章介紹做者在項目中最經常使用到的LLDB命令調試方法。git
LLDB是新一代高性能調試器。 它構建爲一組可重用的組件,能夠高度利用較大的LLVM項目中的現有庫,例如Clang表達式解析器和LLVM反彙編程序。 LLDB是Mac OS X上Xcode的默認調試器,支持在桌面和iOS設備和模擬器上調試C,Objective-C和C ++。 LLDB項目中的全部代碼都是在標準LLVM許可證下提供的,這是一種開源的「BSD風格」許可證。 更多介紹可從LLDB Homepage獲取。github
LLDB命令格式以下: <命令名稱> <命令動做> [-可選項 [可選項的值]] [參數1 [參數2...]]
express
LLDB命令的各部分由空格分割,若是參數中包含空格,則須要使用雙引號括起參數,若是參數中包含雙引號或者反斜槓,則須要使用反斜槓進行轉義。編程
LLDB命令有很是多的功能,徹底背下來不太容易,也不必。開發者可使用help
命令查看相關命令的用法,甚至能夠查看help
命令的用法。bash
(lldb) help help
Show a list of all debugger commands, or give details about a specific
command.
Syntax: help [<cmd-name>]
Command Options Usage:
help [-ahu] [<cmd-name> [<cmd-name> [...]]]
-a ( --hide-aliases )
Hide aliases in the command list.
-h ( --show-hidden-commands )
Include commands prefixed with an underscore.
-u ( --hide-user-commands )
Hide user-defined commands from the list.
This command takes options and free-form arguments. If your arguments
resemble option specifiers (i.e., they start with a - or --), you must use
' -- ' between the end of the command options and the beginning of the
arguments.
複製代碼
在LLDB中,執行命令expression
是最基礎的命令,簡寫爲expr
或者e
,語法爲:expression <cmd-options> -- <expr>
,它的做用是執行一個表達式,並輸出表達式返回的結果。示例以下。微信
//! 輸出count的值
(lldb) expression count
(NSUInteger) $0 = 10
//! 執行string的拼接字符串方法
(lldb) expression [string stringByAppendingString:@"732"]
(__NSCFString *) $1 = 0x00006000006ac870 @"QiShare732"
//! 修改view的顏色
(lldb) expression self.view.backgroundColor = [UIColor redColor]
(UICachedDeviceRGBColor *) $2 = 0x0000600001d74780
(lldb) expression [CATransaction flush]
//!< 由於斷點會終止UI線程,執行[CATransaction flush]命令能夠渲染出修改後的界面
複製代碼
打印命令print
是最經常使用的命令,簡寫爲pri
或者p
,語法爲:print <expr>
,它的做用是打印變量或者表達式。經過help print
會發現print實際上是expression --
命令的簡寫:'print' is an abbreviation for 'expression --'
,其中--
標識選項的結束和參數的開始。 一樣經常使用的expression
簡寫命令還有po
和call
。其中po
表示print object
,用來打印對象,call
用來調用某個方法。示例以下:網絡
(lldb) expression -- self.view
(UIView *) $4 = 0x00007f8ca8401690
(lldb) e self.view
(UIView *) $5 = 0x00007f8ca8401690
(lldb) p self.view
(UIView *) $6 = 0x00007f8ca8401690
(lldb) po self.view
<UIView: 0x7f8ca8401690; frame = (0 0; 375 812); autoresize = W+H; layer = <CALayer: 0x6000008a1dc0>>
(lldb) call self.view
(UIView *) $8 = 0x00007f8ca8401690
複製代碼
另外,開發者能夠按照print/<fmt>
的語法爲print
命令指定打印格式:app
p/x //!< 以十六進制打印整數
p/d //!< 以帶符號的十進制打印整數
p/u //!< 以無符號的十進制打印整數
p/o //!< 以八進制打印整數
p/t //!< 以二進制打印整數
p/a //!< 以十六進制打印地址
p/c //!< 打印字符常量
p/f //!< 打印浮點數
p/s //!< 打印字符串
p/r //!< 格式化打印
複製代碼
示例以下:ide
(lldb) p count
(NSUInteger) $0 = 10
(lldb) p/t count
(NSUInteger) $1 = 0b0000000000000000000000000000000000000000000000000000000000001010
(lldb) p/o count
(NSUInteger) $2 = 012
(lldb) p/x count
(NSUInteger) $3 = 0x000000000000000a
(lldb) p/x string
(__NSCFConstantString *) $4 = 0x000000010416a0b8 @"QiShare"
(lldb) p/c string
(__NSCFConstantString *) $5 = \xb8\xa0\x16\x04\x01\0\0\0 @"QiShare"
(lldb) p/s string
(__NSCFConstantString *) $6 = @"QiShare"
(lldb) p/a string
(__NSCFConstantString *) $7 = 0x000000010416a0b8 @"QiShare" @"QiShare"
複製代碼
thread
是線程相關的命令,語法爲thread <subcommand> [<subcommand-options>]
,它能夠接受不一樣的可選參數,以實現豐富的功能。其中thread list
、thread backtrace
和thread return
較爲經常使用。 開發者可使用thread list
命令查看當前的全部線程,示例以下:
(lldb) thread list
Process 4031 stopped
* thread #1: tid = 0x25cac, 0x0000000104167e23 QiDebugDemo`-[QiConsoleViewController testLLDBCommands](self=0x00007f850df0bbf0, _cmd="testLLDBCommands") at QiConsoleViewController.m:34, queue = 'com.apple.main-thread', stop reason = breakpoint 4.1
thread #2: tid = 0x25d2f, 0x00000001079ff28a libsystem_kernel.dylib`__workq_kernreturn + 10
thread #3: tid = 0x25d30, 0x00000001079ff28a libsystem_kernel.dylib`__workq_kernreturn + 10
thread #4: tid = 0x25d31, 0x00000001079ff28a libsystem_kernel.dylib`__workq_kernreturn + 10
thread #5: tid = 0x25d32, 0x00000001079ff28a libsystem_kernel.dylib`__workq_kernreturn + 10
thread #6: tid = 0x25d33, 0x00000001079ff28a libsystem_kernel.dylib`__workq_kernreturn + 10
thread #7: tid = 0x25d3e, 0x00000001079f520a libsystem_kernel.dylib`mach_msg_trap + 10, name = 'com.apple.uikit.eventfetch-thread'
複製代碼
thread backtrace
命令能夠方便地供開發者查看線程堆棧信息,簡寫爲bt
。好比,當程序崩潰的時候,開發者能夠查看堆棧調用列表。示例以下。
(lldb) thread backtrace
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 2.1
frame #0: 0x0000000104cc2705 libobjc.A.dylib`objc_exception_throw
frame #1: 0x00000001056704ec CoreFoundation`_CFThrowFormattedException + 194
frame #2: 0x00000001057a6b00 CoreFoundation`-[__NSArrayI objectAtIndexedSubscript:] + 96
* frame #3: 0x00000001043a1df7 QiDebugDemo`-[QiConsoleViewController testLLDBCommands](self=0x00007fadc7c50400, _cmd="testLLDBCommands") at QiConsoleViewController.m:33
frame #4: 0x00000001043a1d5a QiDebugDemo`-[QiConsoleViewController viewDidLoad](self=0x00007fadc7c50400, _cmd="viewDidLoad") at QiConsoleViewController.m:26
...
frame #18: 0x00000001056830be CoreFoundation`__CFRunLoopDoObservers + 430
frame #19: 0x0000000105683751 CoreFoundation`__CFRunLoopRun + 1537
frame #20: 0x0000000105682e11 CoreFoundation`CFRunLoopRunSpecific + 625
frame #21: 0x000000010ddd51dd GraphicsServices`GSEventRunModal + 62
frame #22: 0x000000010a1db81d UIKitCore`UIApplicationMain + 140
frame #23: 0x00000001043a2450 QiDebugDemo`main(argc=1, argv=0x00007ffeeb85df90) at main.m:7
frame #24: 0x0000000107858575 libdyld.dylib`start + 1
複製代碼
在調試過程當中,開發者可使用thread return
命令終端某個方法並返回一個想要的值。示例以下。
(lldb) thread return string
(lldb) continue
2019-02-27 17:22:47.323225+0800 QiDebugDemo[5071:222700] resultString: Qi_Share
複製代碼
做者在iOS 調試方法:斷點這篇文章中介紹過斷點的用法。其實,可視化的斷點均可以使用LLDB語法來實現。好比下圖中的一、二、三、四、5都能用LLDB命令表達。
在斷點相關操做中,由於Xcode已經集成了可視化的斷點操做工具,因此breakpoint
命令並不被經常使用。可是,breakpoint
命令擁有着十分強大的功能,語法爲:breakpoint <subcommand> [<command-options>]
,主要命令示例以下。
//! 查看全部斷點
(lldb) breakpoint list
//! 爲全部類中的viewDidAppear:設置斷點
(lldb) breakpoint set -n viewDidAppear:
//! 爲QiConsoleViewController.m文件中的testLLDBCommands方法設定斷點
(lldb) breakpoint set -f QiConsoleViewController.m -n testLLDBCommands
//! 爲QiConsoleViewController.m文件中的第32行代碼設定斷點
(lldb) breakpoint set -f QiConsoleViewController.m -l 32
//! 爲handleString:方法設定條件斷點,條件爲string != nil
(lldb) breakpoint set - handleString: -c string != nil
複製代碼
想比較於breakpoint
是對方法生效的斷點,watchpoint
則是對地址生效的斷點。watchpoint
相似於KVO的工做原理,當觀察到屬性地址裏面的東西改變時,就讓程序中斷,其語法爲:watchpoint <subcommand> [<command-options>]
。其應用場景示例以下。
(lldb) watchpoint set variable string
Watchpoint created: Watchpoint 1: addr = 0x7ffeef497360 size = 8 state = enabled type = w
declare @ '/Users/huangxianshuai/Desktop/Products/QiShare/QiDebugDemo/QiDebugDemo/QiConsoleViewController.m:33'
watchpoint spec = 'string'
new value: 0x00000001007670b8
(lldb) next
Watchpoint 1 hit:
old value: 0x00000001007670b8
new value: 0x0000000100767138
(lldb) image lookup -a 0x00000001007670b8
Address: QiDebugDemo[0x00000001000040b8] (QiDebugDemo.__DATA.__cfstring + 32)
Summary: @"QiShare"
(lldb) image lookup -a 0x0000000100767138
Address: QiDebugDemo[0x0000000100004138] (QiDebugDemo.__DATA.__cfstring + 160)
Summary: @"huang"
複製代碼
image lookup -a
是image lookup -address
的簡寫,能夠查看參數地址的內容。
文章僅列舉了做者日常使用到的一些LLDB命令,這些命令的確能提升調試效率。而更多的LLDB命令能夠從LLDB Homepage或者其餘網絡資源中獲取。
小編微信:可加並拉入《QiShare技術交流羣》。
關注咱們的途徑有:
QiShare(簡書)
QiShare(掘金)
QiShare(知乎)
QiShare(GitHub)
QiShare(CocoaChina)
QiShare(StackOverflow)
QiShare(微信公衆號)
推薦文章:
iOS消息轉發
iOS 自定義拖拽式控件:QiDragView
iOS 自定義卡片式控件:QiCardView
iOS Wireshark抓包
iOS Charles抓包
奇舞週刊