iOS开发断点调试高级技巧

关于LLDB调试,很多iOS开发者可能就是停留在会下简单的断点,使用最多命令也就是po。无可厚非,这些简单的调试对于简单的问题来说应该是游刃有余。但是如果稍微复杂一些的问题,比如我之前遇到过友盟SDK里面的一个问题。我很想往里面下一个断点,可是对于.a的静态库来说,这根本不可能,最终还是我们组大牛使用命令的方式下了断点解决了这个问题。感觉这些知识很有必要,我于是把LLDB的基本调试命令都学习了一下,并在此与大家分享。

虽然博客很长,不过耐心看完,然后动手实践,一定会有很大帮助。

breakpoint

给某个文件的某一行下断点。可以使用如下两种方法,比如我想给Foo.m文件的26行下一个断点。可以使用如下的方法。

(lldb) breakpoint set --file Foo.m --line 26
  • 1
  • 1

如果出现如下提示则说明设置断点成功

Breakpoint 2: where = BreakPointDemo`-[Foo foo] + 23 at Foo.m:26, address = 0x000000010b22e687
  • 1
  • 2
  • 1
  • 2

也可以使用简写的形式如下。

(lldb) breakpoint set -f Foo.m -l 26
  • 1
  • 1

当然我们也可以直接给某个函数下断点,可以使用下面两种方法

(lldb) breakpoint set --name foo
(lldb) breakpoint set -n foo
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3

当然我们也可以在一次命令中为下多个函数下断点

(lldb) breakpoint set --name foo --name bar
  • 1
  • 2
  • 1
  • 2

我们也可以更明确的指定是方法,如果是C的方法,可以使用如下两种的方法打断点,第二种方法M需要大写

(lldb) breakpoint set --method cplusFoo
(lldb) breakpoint set -M cplusFoo
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3

如果是OC的方法,可以使用以下两种方式打断点,第二种S需要大写

(lldb) breakpoint set --selector foo

(lldb) breakpoint set -S foo
  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4

如果是C语言,还是只能使用上面介绍的–name的方式,不能直接指定对应的方法

当然,还有一个必杀器,就是使用正则,匹配你要打断点的函数。这个不限语言

(lldb) breakpoint set -r cFoo
(lldb) breakpoint set -r foo
  • 1
  • 2
  • 1
  • 2

也可以指定加载的动态库

(lldb) breakpoint set --shlib foo.dylib --name foo
(lldb) breakpoint set -s foo.dylib -n foo
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3

我们同样可以对命令进行简写。下面两个命令的效果是一样的

(lldb) breakpoint set -n "-[Foo foo]"
(lldb) br s -n "-[Foo foo]"
  • 1
  • 2
  • 1
  • 2

想要查看有多少断点可以使用

(lldb) breakpoint list
  • 1
  • 1

打印的结果如下

Current breakpoints:
1: file = ‘/Users/jianquan/Xcode/BreakPointDemo/BreakPointDemo/ViewController.m‘, line = 20, exact_match = 0, locations = 0 (pending)
2: file = ‘/Users/jianquan/Xcode/BreakPointDemo/BreakPointDemo/ViewController.mm‘, line = 33, exact_match = 0, locations = 1, resolved = 1, hit count = 0
  2.1: where = BreakPointDemo`::-[ViewController viewDidLoad]() + 186 at ViewController.mm:34, address = 0x0000000105f8362a, resolved, hit count = 0
......
  • 1
  • 2
  • 3
  • 4
  • 5
  • 1
  • 2
  • 3
  • 4
  • 5

我们可以对断点进行相关的操作,比如在执行到2.1断点的时候打印追踪轨迹。bt是

(lldb) breakpoint command add 2.1
Enter your debugger command(s).  Type ‘DONE‘ to end.
> bt
> DONE
  • 1
  • 2
  • 3
  • 4
  • 5
  • 1
  • 2
  • 3
  • 4
  • 5

除了add,还要delete等命令,这些命令不需要死记硬背,可以使用help命令。

(lldb) help break command

      add    -- Add LLDB commands to a breakpoint, to be executed whenever the
                breakpoint is hit.  If no breakpoint is specified, adds the
                commands to the last created breakpoint.
      delete -- Delete the set of commands from a breakpoint.
      list   -- List the script or set of commands to be executed when the
                breakpoint is hit.
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

要查看更详细的命令用途,使用help <command> <subcommand>.比如查看add命令用法

(lldb) help break command add
......

Enter your Python command(s). Type ‘DONE‘ to end.
> def breakpoint_output (bp_no):
>     out_string = "Hit breakpoint number " + repr (bp_no)
>     print out_string
>     return True
> breakpoint_output (1)
> DONE
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

可以看到其实这里面的命令大部分是Python脚本,不熟悉Python,暂时还没有仔细研究。

watchpoint

这个主要是用于观察变量值的具体变化

比如我需要观察某个变量a的值变化,我可以使用如下命令

(lldb) watchpoint set variable a
  • 1
  • 1

成功添加watchpoint后结果如下。

Watchpoint created: Watchpoint 1: addr = 0x7fff5913ca3c size = 4 state = enabled type = w
    declare @ ‘/Users/jianquan/Xcode/BreakPointDemo/BreakPointDemo/ViewController.mm:25‘
    watchpoint spec = ‘a‘
    new value: 10
  • 1
  • 2
  • 3
  • 4
  • 5
  • 1
  • 2
  • 3
  • 4
  • 5

也可以在这里添加.

然后我们可以设置在a的值变化为某个特定值之后触。

(lldb) watchpoint modify -c ‘(a=100)‘
  • 1
  • 2
  • 1
  • 2

我们这个时候可以看一下具体断点的参数,使用watchpoint list命令

(lldb) watchpoint list
Number of supported hardware watchpoints: 4
Current watchpoints:
Watchpoint 1: addr = 0x7fff4fcb7a3c size = 4 state = enabled type = w
    declare @ ‘/Users/jianquan/Xcode/BreakPointDemo/BreakPointDemo/ViewController.mm:25‘
    watchpoint spec = ‘a‘
    new value: 10
    condition = ‘(a=100)‘
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

可以看到我们观察的变量的地址,声明变量的代码在第几行,已经具体的变量名是a,当前的值是10,触发的条件是‘(a=100)‘

然后我们执行如下命令,就可以看到断点到a的值变为100的地方

(lldb) c
Process 16596 resuming
2017-02-09 11:12:14.693 BreakPointDemo[16596:6050498] foo is foo
2017-02-09 11:12:14.693 BreakPointDemo[16596:6050498] bar is bar

Watchpoint 1 hit:
old value: 10
new value: 100
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

可以看到这个地方a的值已经发生改变。我们可以再使用watchpoint list命令看看具体值的变化

(lldb) watchpoint list
Number of supported hardware watchpoints: 4
Current watchpoints:
Watchpoint 1: addr = 0x7fff4fcb7a3c size = 4 state = enabled type = w
    declare @ ‘/Users/jianquan/Xcode/BreakPointDemo/BreakPointDemo/ViewController.mm:25‘
    watchpoint spec = ‘a‘
    old value: 10
    new value: 100
    condition = ‘(a=100)‘
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

当然,还有一个特别好用的命令就是bt命令我们可以用它来追踪程序运行的过程。

(lldb) bt
* thread #1: tid = 0x5c52c2, 0x000000010ff465fe BreakPointDemo`::-[ViewController viewDidLoad](self=0x00007f932cc07c50, _cmd="viewDidLoad") + 158 at ViewController.mm:36, queue = ‘com.apple.main-thread‘, stop reason = watchpoint 1
  * frame #0: 0x000000010ff465fe BreakPointDemo`::-[ViewController viewDidLoad](self=0x00007f932cc07c50, _cmd="viewDidLoad") + 158 at ViewController.mm:36
    frame #1: 0x000000011112ba3d UIKit`-[UIViewController loadViewIfRequired] + 1258
 ......
  • 1
  • 2
  • 3
  • 4
  • 5
  • 1
  • 2
  • 3
  • 4
  • 5

我们可以使用frame命令查看变量a的具体值。

(lldb) frame variable a
(int) a = 100
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3

最后补充一点watchpoint list的东西。这个命令包括了三个可选参数,我们可以使用help命令查看具体的值

(lldb) help watchpoint list

       -b ( --brief )
            Give a brief description of the watchpoint (no location info).

       -f ( --full )
            Give a full description of the watchpoint and its locations.

       -v ( --verbose )
            Explain everything we know about the watchpoint (for debugging
            debugger bugs).
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

-b是比较简略的信息,-f是比较全面的信息,-v是完整的信息。经过我的实验,如果使用watchpoint list,默认的是 watchpoint list -f

process

使用process命令也可以做很多有趣的操作。具体能做什么,我们也可使用help命令查看

(lldb) process help

      attach    -- Attach to a process.
      connect   -- Connect to a remote debug service.
      continue  -- Continue execution of all threads in the current process.
      detach    -- Detach from the current target process.
      handle    -- Manage LLDB handling of OS signals for the current target
    ......
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

查看更详细的命令使用help <command> <subcommand>。比如

(lldb) help process attach
  • 1
  • 2
  • 1
  • 2

这些命令在我目前日常开发中其实不怎么使用,可能我功力还不足吧。

thread

其实这个功能主要就是断点调试里面的如下这个功能。

我们可以使用thread命令来做一些断点的操作,具体有那些命令我们可以使用thread help进行查看。

(lldb) thread help

      ......

      select         -- Change the currently selected thread.
      step-in        -- Source level single step, stepping into calls.
                        Defaults to current thread unless specified.
      step-inst      -- Instruction level single step, stepping into calls.
                        Defaults to current thread unless specified.
      step-inst-over -- Instruction level single step, stepping over calls.
                        Defaults to current thread unless specified.
      step-out       -- Finish executing the current stack frame and stop after
                        returning.  Defaults to current thread unless
                        specified.
      step-over      -- Source level single step, stepping over calls.
                        Defaults to current thread unless specified.
      step-scripted  -- Step as instructed by the script class passed in the -C
                        option.
      until          -- Continue until a line number or address is reached by
                        the current or specified thread.  Stops when returning
                        from the current function as a safety measure.
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

用得比较多的应该是 step-开头的这几个命令,使用起来很容易。我个人感觉比用鼠标点击断点好用多了~

EXAMINING THREAD STATE

这个使用的也主要还是thread命令,主要是使用以下几个命令。

检查当前进程的状态,可以使用如下命令。

lldb)  thread list
Process 22323 stopped
* thread #1: tid = 0x62d0d7, 0x00000001082185fe BreakPointDemo`::-[ViewController viewDidLoad](self=0x00007ff81b60ab20, _cmd="viewDidLoad") + 158 at ViewController.mm:36, queue = ‘com.apple.main-thread‘, stop reason = step until
......
  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4

*表明的就是当前的线程,可以使用如下的命令得到线程的回溯,这个词我也不确定怎么表达好,backtrace,也可以说是追踪。

 lldb) thread backtrace
* thread #1: tid = 0x62d0d7, 0x00000001082185fe BreakPointDemo`::-[ViewController viewDidLoad](self=0x00007ff81b60ab20, _cmd="viewDidLoad") + 158 at ViewController.mm:36, queue = ‘com.apple.main-thread‘, stop reason = step until
  * frame #0: 0x00000001082185fe BreakPointDemo`::-[ViewController viewDidLoad](self=0x00007ff81b60ab20, _cmd="viewDidLoad") + 158 at ViewController.mm:36
    frame #1: 0x00000001093fda3d UIKit`-[UIViewController loadViewIfRequired] + 1258
    frame #2: 0x00000001093fde70 UIKit`-[UIViewController view] + 27
    frame #3: 0x00000001092c74b5 UIKit`-[UIWindow addRootViewControllerViewIfPossible] + 71
    frame #4: 0x00000001092c7c06 UIKit`-[UIWindow _setHidden:forced:] + 293
    frame #5: 0x00000001092db519 UIKit`-[UIWindow makeKeyAndVisible] + 42
    frame #6: 0x0000000109253f8d UIKit`-[UIApplication _callInitializationDelegatesForMainScene:transitionContext:] + 4818
    frame #7: 0x000000010925a0ed UIKit`-[UIApplication _runWithMainScene:transitionContext:completion:] + 1731
    frame #8: 0x000000010925726d UIKit`-[UIApplication workspaceDidEndTransaction:] + 188
    frame #9: 0x000000010c3886cb FrontBoardServices`__FBSSERIALQUEUE_IS_CALLING_OUT_TO_A_BLOCK__ + 24
    frame #10: 0x000000010c388544 FrontBoardServices`-[FBSSerialQueue _performNext] + 189
    frame #11: 0x000000010c3888cd FrontBoardServices`-[FBSSerialQueue _performNextFromRunLoopSource] + 45
    frame #12: 0x0000000108ddc761 CoreFoundation`__CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 17
    frame #13: 0x0000000108dc198c CoreFoundation`__CFRunLoopDoSources0 + 556
    frame #14: 0x0000000108dc0e76 CoreFoundation`__CFRunLoopRun + 918
    frame #15: 0x0000000108dc0884 CoreFoundation`CFRunLoopRunSpecific + 420
    frame #16: 0x0000000109255aea UIKit`-[UIApplication _run] + 434
    frame #17: 0x000000010925bc68 UIKit`UIApplicationMain + 159
    frame #18: 0x000000010821899f BreakPointDemo`main(argc=1, argv=0x00007fff579e7600) + 111 at main.m:14
    frame #19: 0x000000010bbee68d libdyld.dylib`start + 1
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

当然我们如果想看所有线程的backtrace,可以使用thread backtrace all命令。内容太多,我这里就不演示log输出了。

如果我们想单独查看某个线程,我们可以先使用thread select 2跳到某个具体的线程,然后再进行其他操作,比如thread backtrace

EXAMINING STACK FRAME STATE

为了方便的观测架构参数和本地变量,我们可以使用 frame variable 命令

如果我什么参数也不加,将会把所有的参数和本地变量到打印出来。

(lldb) frame variable
(ViewController *) self = 0x00007ff81b60ab20
(SEL) _cmd = "viewDidLoad"
(int) a = 100
(Foo *) foo = 0x000061800000e820
(BreakPointDemoNameSpace::BreakPointClass *) cplusFoo = 0x3ff0000000000000
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

要打印某个变量需要在参数里面指定,这个命令我们在前面也使用过,比如要查看self

(lldb) frame variable self
(ViewController *) self = 0x00007ff81b60ab20
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3

更进一步,我们可以查看一些子元素

(lldb) frame variable self->isa
(Class) self->isa = ViewController
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3

命令虽然不是完整的表达式解释器,当时可以识别一些基本的操作 比如 &, *, ->, [],不是重载运算符,数组也可以使用,因为数组本身也是指针。

(lldb) frame variable *self 

(ViewController) *self = {
  UIViewController = {
    UIResponder = {
      NSObject = {
        isa = ViewController
      }
    ......
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

和之前thread命令很类似,我可以使用frame select去选择另外的一个frame

(lldb) frame select 9
  • 1
  • 2
  • 1
  • 2

如果想看更复杂的数据,我们可以使用expression命令

(lldb) expression self
(ViewController *) $0 = 0x00007fefa4705110
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3

更复杂一些,我们可以用来输出一个表达式

(lldb) expr (int) printf ("I have a pointer 0x%llx.\n", self)
I have a pointer 0x7fefa4705110.
(int) $1 = 33
  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4

我们可以继续以之前的命令来操作

(lldb) expr self = $0
(ViewController *) $2 = 0x00007fefa4705110
  • 1
  • 2
  • 1
  • 2

当然这个expr用途感觉不大。

call

其实这个命令完全可以使用po进行替代,call一般可以用来调用不需要返回值的调试命令,比如更改View的背景颜色,以下两个命令都可以达到相似的作用,更改当前View的背景颜色值。

(lldb) po [self.view setBackgroundColor:[UIColor redColor]]
(lldb) call [self.view setBackgroundColor:[UIColor redColor]]
  • 1
  • 2
  • 1
  • 2

image

虽然只是一个简单的命令,但是我还是感觉这是一个比较重要也比较实用的命令, 命令可用于寻址。比较实用的用法是用于寻找栈地址对应的代码位置。 下面我写了一段代码

  //测试image命令使用
    NSArray *arr=[[NSArray alloc] initWithObjects:@"1",@"2", nil];
    NSLog(@"%@",arr[2]);
  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4

可以很明显的看到数组越界了,然后我们运行程序,可以看到程序报如下错误

this is cplusFoothis is cFoo2017-02-09 16:33:52.143 BreakPointDemo[26121:6901793] *** Terminating app due to uncaught exception ‘NSRangeException‘, reason: ‘*** -[__NSArrayI objectAtIndex:]: index 2 beyond bounds [0 .. 1]‘
*** First throw call stack:
(
    0   CoreFoundation                      0x0000000104d67d4b __exceptionPreprocess + 171
    1   libobjc.A.dylib                     0x000000010471e21e objc_exception_throw + 48
    2   CoreFoundation                      0x0000000104ca22bb -[__NSArrayI objectAtIndex:] + 155
    3   BreakPointDemo                       -[ViewController viewDidLoad] + 340
    4   UIKit                               0x000000010675ba3d -[UIViewController loadViewIfRequired] + 1258
    5   UIKit                               0x000000010675be70 -[UIViewController view] + 27
    6   UIKit                               0x00000001066254b5 -[UIWindow addRootViewControllerViewIfPossible] + 71
    7   UIKit                               0x0000000106625c06 -[UIWindow _setHidden:forced:] + 293
    8   UIKit                               0x0000000106639519 -[UIWindow makeKeyAndVisible] + 42
    9   UIKit                               0x00000001065b1f8d -[UIApplication _callInitializationDelegatesForMainScene:transitionContext:] + 4818
    10  UIKit                               0x00000001065b80ed -[UIApplication _runWithMainScene:transitionContext:completion:] + 1731
    11  UIKit                               0x00000001065b526d -[UIApplication workspaceDidEndTransaction:] + 188
    12  FrontBoardServices                  0x00000001083456cb __FBSSERIALQUEUE_IS_CALLING_OUT_TO_A_BLOCK__ + 24
    13  FrontBoardServices                  0x0000000108345544 -[FBSSerialQueue _performNext] + 189
    14  FrontBoardServices                  0x00000001083458cd -[FBSSerialQueue _performNextFromRunLoopSource] + 45
    15  CoreFoundation                      0x0000000104d0c761 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 17
    16  CoreFoundation                      0x0000000104cf198c __CFRunLoopDoSources0 + 556
    17  CoreFoundation                      0x0000000104cf0e76 __CFRunLoopRun + 918
    18  CoreFoundation                      0x0000000104cf0884 CFRunLoopRunSpecific + 420
    19  UIKit                               0x00000001065b3aea -[UIApplication _run] + 434
    20  UIKit                               0x00000001065b9c68 UIApplicationMain + 159
    21  BreakPointDemo                      0x000000010414794f main + 111
    22  libdyld.dylib                       0x00000001062b068d start + 1
    23  ???                                 0x0000000000000001 0x0 + 1
)

libc++abi.dylib: terminating with uncaught exception of type NSException
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31

我们大概可以猜测程序是崩溃在第三行log,也就是地址为0x0000000104147544的地方,怎么来呢,瞎猜的,哈哈。其实原理很简单,因为我的Demo名字叫BreakPointDemo。其他的名字很明显是系统的库。虽然log的21行也有BreakPointDemo,但是经过观察应该是main函数,不在考虑范围之内。

我们使用imagelookup命令,可以很快的定位到具体的代码行。

(lldb) image lookup --address 0x0000000104147544
      Address: BreakPointDemo[0x0000000100001544] (BreakPointDemo.__TEXT.__text + 644)
      Summary: BreakPointDemo`::-[ViewController viewDidLoad]() + 340 at ViewController.mm:46
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3

看看我们的Xcode文件的代码。确实是46行

当然还有很多的命令我们可以探索,使用image help可以查看,这些命令我暂时没有接触过,后续工作或者学习中使用到了我会更新上来。

为命令设置别名

比如pframe variable的别名,p view实际上是frame variable view。除了系统自建的LLDB别名,你也可以自定义别名。比如下面这个命令。掌握了规律之后,任何的命令我们都可以自己设置别名。

(lldb) command alias bfl breakpoint set -f %1 -l %2
(lldb) bfl Foo.m 12
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3

如果想要撤销别名使用

(lldb) command unalias bfl
时间: 2024-10-17 15:13:37

iOS开发断点调试高级技巧的相关文章

iOS开发中调试的总结

本博客转自:http://www.jianshu.com/p/9c4c92a38468 [1.普通断点] 断点(Breakpoint)绝对是调试程序的第一大选择,也是掌握的基础技能.顾名思义,当程序运行到断点处时会暂停运行.比如断点打在11行,那么程序就会停在11行(注意:程序只运行到了前10行,第11行其实还没有被执行!!!).只要在代码行旁边点击,就能添加一个断点,再次点击,就能让断点不可用(disable了,仍然存在,只是不起作用了).在某一行创建断点的快捷键是:command+\ 并能在

iOS开发UI调试神器----Reveal

做iOS的开发,UI是非常非常重要的一环.调试时我们一般用模拟器,提交前用真机做測试.用模拟器来调试UI效果尽管快捷方便,但有时仍然希望有更强大的工具来帮助分析UI,尤其是专注在UI的效果调试时.近期看到了Reveal这个工具,发现真的是强大无比,类似于FireFox上的FireBug,对于UI上的层的显示非常清晰直观,能够非常方便的用于UI的调试,用来学习UI的使用也是无上利器. 这个工具眼下已经出到正式版了,须要花费银子购买,好在还有30天的试用版本号能够下载尝尝鲜.(下载地址http://

iOS开发 僵尸调试

本文转载至 http://blog.sina.com.cn/s/blog_a843a8850101dxin.html 引自:http://blog.csdn.net/likendsl/article/details/7566305 我的摘要: 1.为什么会使用NSZombieEnabled? 应用调试可能会收到类似 Thread 1: Program received signal:"EXC_BAD_ACCESS 这样的错误提示信息,这样的信息通常是内存操作错误引起,例如你对已释放的对象发送消息

iOS开发Safari调试WebView页面

App混合开发现已是常态,不过作为app端开发人员,对H5页面的使用,可不能简单的局限于使用,一些简单的调试方法还是有必要了解的. 关于如何在使用webview过程中,如何对web内对内容进行调试,这里会简单讲一下步骤. 一.真机或Simulator  打开"设置"->"Safari"->"高级"->"Web检查器" 二.打开电脑上 Safari  ->"偏好设置" -> &q

IOS开发中一些受用的编码和调试方法积累

1.## 与 @# 在宏里面该怎样使用 ##的使用, 首先我们添加一个宏 1 #define LRWeakSelf(type) __weak typeof(type) weak##type = type; ##是连接的作用, 即当使用上面的宏会把weak与输入的type值连接起来如下图: #的意思是紧跟着它的后面的标识符添加一个双引号""@#的使用, 我们添加一个普通的宏: 1 #define LRToast(str) [NSString stringWithFormat:@"

ios开发视频播放后台下载功能实现 :1,ios播放视频 ,包含基于AVPlayer播放器,2,实现下载,iOS后台下载(多任务同时下载,单任务下载,下载进度,下载百分比,文件大小,下载状态)(真机调试功能正常)

ABBPlayerKit ios开发视频播放后台下载功能实现 : 代码下载地址:https://github.com/niexiaobo/ABBPlayerKit github资料学习和下载地址:https://github.com/niexiaobo/ 实现功能 :播放视频 ,视频后台下载 (真机调试功能正常) 1.使用ZFPlayer播放视频(可以在线和本地播放,基于AVPlayer,调节音量和屏幕亮度) 2.使用 WHCNetWorkKit 实现下载,后台下载(多任务同时下载,单任务下载,

iOS开发调试技巧总结(持续更新中)

作者:乞力马扎罗的雪  原文 对于软件开发而言,调试是必须学会的技能,重要性不言而喻.对于调试的技能,基本上是可以迁移的,也就是说你以前在其他平台上掌握的很多调试技巧,很多也是可以用在iOS开发中.不同语言.不同IDE.不同平台的调试,有同性也有个性.今天我们就来学习一下iOS开发中的调试技巧,语言暂用为OC,IDE当然是强大的Xcode.首先说明下,Xcode已经为我们调试项目提供了极大的方便. [1.普通断点] 断点(Breakpoint)绝对是调试程序的第一大选择,也是掌握的基础技能.顾名

iOS 开发常用的调试命令

XCode4.0以后,编译器是LLVM,控制台调试命令前缀是lldb 第一.LLVM简介 LLVM是构架编译器(compiler)的框架系统,以C++编写而成,用于优化以任意程序语言编写的程序的编译时间(compile-time).链接时间(link-time).运行时间(run-time)以及空闲时间(idle-time),对开发者保持开放,并兼容已有脚本. 第二. 对关注编译技术的开发人员,LLVM提供了很多优点: 现代化的设计 LLVM的设计是高度模块化的,使得其代码更为清晰和便于排查问题

.NET C#微信公众号开发远程断点调试(本地远程调试生产环境)

最近在做微信公众号开发,由于之前没有接触过,突然发现调试不方便,不方便进行断点跟踪调试.因为微信那边绑定的服务器地址必须是公网地址,但是还是想进行断点调试(毕竟这样太方便了) 因此上网搜了一下,发现好多是使用软件之类的进行请求转发从生产环境转发请求到开发环境上,发现有的太麻烦了. 突然想到Vs有一个附加到进程的远程调试.于是玩了一把.我们直接开始(服务器上就不要使用发布版本代码了,代码和本地开发一样,不然是不能调试的) 本篇是以开发环境的Visual Studio2013旗舰版以及生产环境里阿里