原创Blog,转载请注明出处
http://blog.csdn.net/hello_hwc?viewmode=list
我的stackoverflow
前言:LLDB是个开源的调试器,与XCode绑定的
LLDB的使用中,Swift与Objective C还是有一些差别的
本文主要侧重LLDB的常用命令
资料(目前状态XCode 7.2 Swift 2.1.1),非XCode 7.2+本文代码可能不能运行
- objc.io(强烈建议有Objective C经验,但是对LLDB不熟悉的深入研究下)
- Apple官方文档
- LLDB的文档
- 一个封装LLDB的库,可以辅助调试
- 2015 WWDC视频
对了,Swift到现在也不过一岁半,所以LLDB对于Swift的支持肯定不如OC那么好。
如何打开LLDB如何使用?
通常的方式就是断点,另外,关于利用XCode图形化调试,在我这篇文章里有详细讲解
本文适合XCode 7.2 +
不管是在程序中加断点
还是手动的暂停程序
让代码停在Swift Error 或者Objective C异常
停在Objective C异常
- (lldb) br s -E objc
- Breakpoint 6: where = libobjc.A.dylib`objc_exception_throw,address = 0x000000010dededbb
停在Swift Error
- (lldb) br s -E swift
- Breakpoint 7: where = libswiftCore.dylib`swift_willThrow,address = 0x000000010e55ccc0
停在某一种类型的Swift Error
- (lldb) br s -E swift -O EnumError
- Breakpoint 8: where = libswiftCore.dylib`swift_willThrow,address = 0x000000010e55ccc0
以此作为开端,希望读者能耐心看完,本文很长
准备工作
为了方便,我们先写好这样的一个Model类,定义个ErrorType,并且定义个实例方法抛出异常
- enum CustomError:ErrorType{
- case LeoError1
- case LeoError2
- }
- class Person:NSObject{
- var name:String
- var age:UInt32
- init(name:String,age:UInt32){
- self.name = name
- self.age = age
- }
- //重写description是为了方便调试
- override var description:String{
- return "name:\(name) age:\(age)"
- }
- func PersonException() throws{
- throw CustomError.LeoError1
- }
- }
然后在viewDidLoad中初始化一个对象,并打一个断点
- let person = Person(name: "Leo",age: 23)
打印命令 p/po
p
- (lldb) p person
- (SwiftLLDBDemo.Person) $R0 = 0x00007f99b8d30b40 {
- ObjectiveC.NSObject = {
- isa = SwiftLLDBDemo.Person
- }
- name = "Leo"
- age = 23
- }
po
- (lldb) po person
- name:Leo age:23
p命令会打印出对象的类型,如果是Objective C对象,会打印出isa,以及属性的值
po 命令 对于继承自NSObject得对象,指示会打印出description中的内容
再举个例子
- (lldb) po ["123","345"]
- ▿ 2 elements
- - [0] : "123"
- - [1] : "345"
-
- (lldb) p ["123","345"]
- ([String]) $R2 = 2 values {
- [0] = "123"
- [1] = "345"
- }
- (lldb) p for i in 1...3{ print(i) }
- 1
- 2
- 3
执行代码 e
expression命令可以帮助我们执行代码,
- (lldb) e person.name = "Jack"
- (lldb) p person
- (SwiftLLDBDemo.Person) $R1 = 0x00007f9bf1424c20 {
- ObjectiveC.NSObject = {
- isa = SwiftLLDBDemo.Person
- }
- name = "Jack"
- age = 23
- }
在这我们深入的研究所有命令
- (lldb) help
内容太多,不拷贝进来了,自己在XCode里敲敲试试吧。
可以看到,有一部分是alias部分,有linux经验的同学应该知道,alias就是将一个简单的命令设置为复杂命令的别名。我们上面讲到的两个命令p/po就是两个alias命令
- p -- ('expression --') Evaluate an expression (ObjC++ or Swift) in
- the current program context,using user defined variables and
- variables currently in scope.
- po -- ('expression -O -- ') Evaluate an expression (ObjC++ or Swift)
- in the current program context,using user defined variables and
- variables currently in scope.
所以,p命令,本质是expression --
;po命令,本质是expression -O --
- (lldb) expression -- person
- (SwiftLLDBDemo.Person) $R0 = 0x00007f96a3f792d0 {
- ObjectiveC.NSObject = {
- isa = SwiftLLDBDemo.Person
- }
- name = "Leo"
- age = 23
- }
- (lldb) expression -O -- person
- name:Leo age:23
更加复杂的执行
例如,动态的修改view的背景色
- e self.view.backgroundColor = UIColor.blueColor
Expression命令很灵活
格式化打印 -f (format)
- (lldb) expr -f bin -- person.age
- (UInt32) $R2 = 0b00000000000000000000000000010111
- (lldb) expr -f oct -- person.age
- (UInt32) $R3 = 027
- (lldb) expr -f hex -- person.age
- (UInt32) $R4 = 0x00000017
格式化打印可以更简单
- (lldb) p/x person.age
- (UInt32) $R5 = 0x00000017
打印Raw value expr -R -- 变量
- (lldb) expr -R -- person
- (SwiftLLDBDemo.Person) $R6 = 0x00007f96a3f792d0 { ObjectiveC.NSObject = {}
- name = { _core = { _baseAddress = { _rawValue = 0x0000000101041298 "Leo" }
- _countAndFlags = { value = 3 }
- _owner = None { Some = { instance_type = 0x0000000000000000 }
- }
- }
- }
- age = { value = 23 }
- }
显示变量类型expr -T -- 变量
- (lldb) expr -T -- person
- (SwiftLLDBDemo.Person) $R7 = 0x00007f96a3f792d0 {
- (NSObject) ObjectiveC.NSObject = {
- (Class) isa = SwiftLLDBDemo.Person
- }
- (String) name = "Leo"
- (UInt32) age = 23
- }
当然也可以结合多个使用expr -RRT -- person
帮助命令,可以再深入看看其他执行选项,不过不是很常用
- help expression
LLDB变量
LLDB的变量和脚本语言类似,以美元符号开头,使用的时候也要带着美元符号,调用的时候和Swift的语法一致
例如
- (lldb) e var $a = 10
- (lldb) p $a
- (Int) $a = 10
-
- (lldb) e var $b = Person(name: "Jack",age: 25)
- (lldb) p $b
- (SWTest.Person) $b = 0x00007f8909539080 {
- ObjectiveC.NSObject = {
- isa = SWTest.Person
- }
- name = "Jack"
- age = 25
- }
断点
断点采用这个命令breakpoint,缩写br
断点命令的文档较少,这里先列出文档
- (lldb) help breakpoint
- The following subcommands are supported:
-
- clear -- Clears a breakpoint or set of breakpoints in the executable.
- command -- A set of commands for adding,removing and examining bits of
- code to be executed when the breakpoint is hit (breakpoint
- 'commands').
- delete -- Delete the specified breakpoint(s). If no breakpoints are specified,delete them all. disable -- Disable the specified breakpoint(s) without removing them. If none are specified,disable all breakpoints. enable -- Enable the specified disabled breakpoint(s). If no breakpoints are specified,enable all of them. list -- List some or all breakpoints at configurable levels of detail. modify -- Modify the options on a breakpoint or set of breakpoints in the executable. If no breakpoint is specified,acts on the last created breakpoint. With the exception of -e,-d and -i,passing an empty argument clears the modification. name -- A set of commands to manage name tags for breakpoints set -- Sets a breakpoint or set of breakpoints in the executable.
breakpoint set -E language
breakpoint s -E swift -O ErrorType
列出断点
- (lldb) br li
- Current breakpoints:
- 1: file = '/Users/huangwenchen/Desktop/SWTest/SWTest/ViewController.swift',line = 27,locations = 1,resolved = 1,hit count = 1
-
- 1.1: where = SWTest`SWTest.ViewController.viewDidLoad (SWTest.ViewController)() -> () + 75 at ViewController.swift:27,address = 0x000000010ef8556b,resolved,hit count = 1
禁用断点
- (lldb) br dis 1
- 1 breakpoints disabled.
删除断点
- (lldb) br del 1
- 1 breakpoints deleted; 0 breakpoint locations disabled.
- (lldb) br li
- No breakpoints currently set.
添加断点
- (lldb) br set -f ViewController.swift -l 28
- Breakpoint 2: where = SWTest`SWTest.ViewController.viewDidLoad (SWTest.ViewController)() -> () + 139 at ViewController.swift:29,address = 0x000000010ef855ab
也可以简写为
- (lldb) b ViewController.swift:28
- Breakpoint 3: where = SWTest`SWTest.ViewController.viewDidLoad (SWTest.ViewController)() -> () + 139 at ViewController.swift:29,address = 0x000000010ef855ab
- (lldb) br li
- Current breakpoints:
- 2: file = 'ViewController.swift',line = 28,hit count = 0
- 2.1: where = SWTest`SWTest.ViewController.viewDidLoad (SWTest.ViewController)() -> () + 139 at ViewController.swift:29,address = 0x000000010ef855ab,hit count = 0
-
- 3: file = 'ViewController.swift',hit count = 0
- 3.1: where = SWTest`SWTest.ViewController.viewDidLoad (SWTest.ViewController)() -> () + 139 at ViewController.swift:29,hit count = 0
断点Name
断点名称是用来管理一组断点的,通过name可以启用或者禁用一组断点,一个断点可以有多个name,很像tag。
- br set -f ViewController.swift -l 28 -N leo
- (lldb) br set -f ViewController.swift -l 28 -N leo
- Breakpoint 2: 3 locations.
- (lldb) br li
- Current breakpoints:
- 1: file = '/Users/huangwenchen/Desktop/SWTest/SWTest/ViewController.swift',line = 34,hit count = 1
-
- 1.1: where = SWTest`SWTest.ViewController.viewDidLoad (SWTest.ViewController)() -> () + 75 at ViewController.swift:34,address = 0x00000001070d51fb,hit count = 1
-
- 2: file = 'ViewController.swift',locations = 3,resolved = 3,hit count = 0
- Names:
- leo
-
- 2.1: where = SWTest`SWTest.ViewController.__deallocating_deinit + 12 at ViewController.swift,address = 0x00000001070d538c,hit count = 0
- 2.2: where = SWTest`SWTest.ViewController.init (SWTest.ViewController.Type)(nibName : Swift.Optional<Swift.String>,bundle : Swift.Optional<__ObjC.NSBundle>) -> SWTest.ViewController + 57 at ViewController.swift,address = 0x00000001070d53f9,hit count = 0
- 2.3: where = SWTest`SWTest.ViewController.init (SWTest.ViewController.Type)(coder : __ObjC.NSCoder) -> Swift.Optional<SWTest.ViewController> + 16 at ViewController.swift,address = 0x00000001070d56d0,hit count = 0
在加上名字以后,我们就可以通过名字来操作断点了
- (lldb) br disable -N leo
- 1 breakpoints disabled.
在某一个函数上加断点
例如,在准备Person的函数中personLoop添加断点
- (lldb) br s -F personLoop
- Breakpoint 2: 2 locations.
- (lldb) br li
- Current breakpoints:
- 1: file = '/Users/huangwenchen/Desktop/SWTest/SWTest/ViewController.swift',line = 40,hit count = 1
-
- 1.1: where = SWTest`SWTest.ViewController.viewDidLoad (SWTest.ViewController)() -> () + 75 at ViewController.swift:40,address = 0x000000010f6d51bb,hit count = 1
-
- 2: name = 'personLoop',locations = 2,resolved = 2,hit count = 0
- 2.1: where = SWTest`SWTest.Person.personLoop (SWTest.Person)() -> () + 12 at ViewController.swift:25,address = 0x000000010f6d45cc,hit count = 0
- 2.2: where = SWTest`@objc SWTest.Person.personLoop (SWTest.Person)() -> () + 4 at ViewController.swift,address = 0x000000010f6d4664,hit count = 0
条件断点
先在这里加一个断点
当某种条件产生的时候触发的断点,例如停在1000次循环的第800次
然后添加条件,停在i == 80
- (lldb) br li
- Current breakpoints:
- 1: file = '/Users/huangwenchen/Desktop/SWTest/SWTest/ViewController.swift',address = 0x00000001094d81bb,hit count = 1
-
- 2: file = '/Users/huangwenchen/Desktop/SWTest/SWTest/ViewController.swift',hit count = 1
-
- 2.1: where = SWTest`SWTest.Person.personLoop (SWTest.Person)() -> () + 111 at ViewController.swift:27,address = 0x00000001094d762f,hit count = 1
-
- (lldb) br modify -c 'i == 80'
- (lldb) po i
- 80
断点行为
当断点触发的时候,执行的LLDB代码
例如,当i==80的时候,输出sum
- (lldb) br li
- Current breakpoints:
- 1: file = '/Users/huangwenchen/Desktop/SWTest/SWTest/ViewController.swift',line = 40,hit count = 1
-
- 1.1: where = SWTest`SWTest.ViewController.viewDidLoad (SWTest.ViewController)() -> () + 75 at ViewController.swift:40,address = 0x00000001057391bb,hit count = 1
-
- 3: file = '/Users/huangwenchen/Desktop/SWTest/SWTest/ViewController.swift',line = 27,hit count = 0
-
- 3.1: where = SWTest`SWTest.Person.personLoop (SWTest.Person)() -> () + 111 at ViewController.swift:27,address = 0x000000010573862f,hit count = 0
-
- (lldb) br modify -c 'i == 80' 3
- (lldb) br command add 3
- Enter your debugger command(s). Type 'DONE' to end.
- > po sum
- > DONE
- po sum
- 3160
其他断点相关
lldb中输入
- (lldb) help br set
篇幅限制,不列出help的结果了
类型查找Type
抛出一个异常,不知道是啥的时候怎么办?
- (lldb) type lookup CustomError
- enum CustomError : ErrorType {
- case LeoError1
- case LeoError2
- var hashValue: Swift.Int {
- get {}
- }
- var _code: Swift.Int {
- get {}
- }
- }
可以简写
- (lldb) ty l CustomError
- enum CustomError : ErrorType {
- case LeoError1
- case LeoError2
- var hashValue: Swift.Int {
- get {}
- }
- var _code: Swift.Int {
- get {}
- }
- }
LLDB中的异常处理
执行一个抛出异常的方法
- (lldb) e person.personException()
- (SWTest.CustomError) $E0 = LeoError1
流程控制
frame info 查看当前所在的位置
- (lldb) frame info
- frame #0: 0x000000010573862f SWTest`SWTest.Person.personLoop (self=0x00007fbaf1d054d0)() -> () + 111 at ViewController.swift:27
- c 继续运行
- n next 下一行
- s step in
- finish step out
函数提前返回
- thread return
通过这个命令,可以很好的隔离函数,通常用在函数的最开始位置,避免ARC引用计数问题
最后
欢饮关注我的CSDN博客,很长一段时间内,我会持续的更新iOS/Swift/Objective C相关的文章
LLDB调试的文章应该还有一篇进阶使用的,近期会更新