美文网首页
iOS 只会用NSLog误区,LLDB, Breakpoint调

iOS 只会用NSLog误区,LLDB, Breakpoint调

作者: 树懒啊树懒 | 来源:发表于2017-11-22 17:56 被阅读117次

本文主要介绍以下几个内容:
1.NSLog使用及上线版本设置
2.运行中任意位置打印日志 : LLDB的po(打印对象),p(基础数据),image(崩溃调试地址信息)等等命令使用
3.运行中随时修改条件执行断点:Breakpoint
4.全局断点模式设置
5.其他

一 : NSLog使用及上线版本设置: 考虑到NSLog会影响到性能,发布版本还是尽量不要打印,那么就要区分版本,

在项目头文件添加下面一段代码即可,项目中所有的 NSLog 在真机运行都不会执行了

#if TARGET_IPHONE_SIMULATOR
#define DEBUG 1      //模拟环境
#elif TARGET_OS_IPHONE
#define DEBUG 0  //真机
#endif

#ifdef DEBUG
#   define NSLog(fmt, ...) NSLog((@"%s [Line %d] " fmt), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__);
#else
#   define NSLog(...)
#endif

二 : 运行中任意位置打印日志 : LLDB的po,p,call 等命令使用

下面简单举一个测试例子:设置一个断点,运行到此截断后,在xcode底部右侧(lldb) 后开始输入命令" po 对象 ",然后回车即可


po命令

当你使用po命令后一定程度上调试可以不用NSLog了吧.
那么lldb到底有多少命令呢? 输入help回车告诉你有很多commands:


help
Debugger commands:
  apropos           -- List debugger commands related to a word or subject.
  breakpoint        -- Commands for operating on breakpoints (see 'help b' for
                       shorthand.)
  bugreport         -- Commands for creating domain-specific bug reports.
  command           -- Commands for managing custom LLDB commands.
  disassemble       -- Disassemble specified instructions in the current
                       target.  Defaults to the current function for the
                       current thread and stack frame.
  expression        -- Evaluate an expression on the current thread.  Displays
                       any returned value with LLDB's default formatting.
  frame             -- Commands for selecting and examing the current thread's
                       stack frames.
  gdb-remote        -- Connect to a process via remote GDB server.  If no host
                       is specifed, localhost is assumed.
  gui               -- Switch into the curses based GUI mode.
  help              -- Show a list of all debugger commands, or give details
                       about a specific command.
  kdp-remote        -- Connect to a process via remote KDP server.  If no UDP
                       port is specified, port 41139 is assumed.
  language          -- Commands specific to a source language.
  log               -- Commands controlling LLDB internal logging.
  memory            -- Commands for operating on memory in the current target
                       process.
  platform          -- Commands to manage and create platforms.
  plugin            -- Commands for managing LLDB plugins.
  process           -- Commands for interacting with processes on the current
                       platform.
  quit              -- Quit the LLDB debugger.
  register          -- Commands to access registers for the current thread and
                       stack frame.
  script            -- Invoke the script interpreter with provided code and
                       display any results.  Start the interactive interpreter
                       if no code is supplied.
  settings          -- Commands for managing LLDB settings.
  source            -- Commands for examining source code described by debug
                       information for the current target process.
  target            -- Commands for operating on debugger targets.
  thread            -- Commands for operating on one or more threads in the
                       current process.
  type              -- Commands for operating on the type system.
  version           -- Show the LLDB debugger version.
  watchpoint        -- Commands for operating on watchpoints.
Current command abbreviations (type 'help command alias' for more info):
  add-dsym  -- Add a debug symbol file to one of the target's current modules
               by specifying a path to a debug symbols file, or using the
               options to specify a module to download symbols for.
  attach    -- Attach to process by ID or name.
  b         -- Set a breakpoint using one of several shorthand formats.
  bt        -- Show the current thread's call stack.  Any numeric argument
               displays at most that many frames.  The argument 'all' displays
               all threads.
  c         -- Continue execution of all threads in the current process.
  call      -- Evaluate an expression on the current thread.  Displays any
               returned value with LLDB's default formatting.
  continue  -- Continue execution of all threads in the current process.
  detach    -- Detach from the current target process.
  di        -- Disassemble specified instructions in the current target. 
               Defaults to the current function for the current thread and
               stack frame.
  dis       -- Disassemble specified instructions in the current target. 
               Defaults to the current function for the current thread and
               stack frame.
  display   -- Evaluate an expression at every stop (see 'help target
               stop-hook'.)
  down      -- Select a newer stack frame.  Defaults to moving one frame, a
               numeric argument can specify an arbitrary number.
  env       -- Shorthand for viewing and setting environment variables.
  exit      -- Quit the LLDB debugger.
  f         -- Select the current stack frame by index from within the current
               thread (see 'thread backtrace'.)
  file      -- Create a target using the argument as the main executable.
  finish    -- Finish executing the current stack frame and stop after
               returning.  Defaults to current thread unless specified.
  image     -- Commands for accessing information for one or more target
               modules.
  j         -- Set the program counter to a new address.
  jump      -- Set the program counter to a new address.
  kill      -- Terminate the current target process.
  l         -- List relevant source code using one of several shorthand formats.
  list      -- List relevant source code using one of several shorthand formats.
  n         -- Source level single step, stepping over calls.  Defaults to
               current thread unless specified.
  next      -- Source level single step, stepping over calls.  Defaults to
               current thread unless specified.
  nexti     -- Instruction level single step, stepping over calls.  Defaults to
               current thread unless specified.
  ni        -- Instruction level single step, stepping over calls.  Defaults to
               current thread unless specified.
  p         -- Evaluate an expression on the current thread.  Displays any
               returned value with LLDB's default formatting.
  parray    -- Evaluate an expression on the current thread.  Displays any
               returned value with LLDB's default formatting.
  po        -- Evaluate an expression on the current thread.  Displays any
               returned value with formatting controlled by the type's author.
  poarray   -- Evaluate an expression on the current thread.  Displays any
               returned value with LLDB's default formatting.
  print     -- Evaluate an expression on the current thread.  Displays any
               returned value with LLDB's default formatting.
  q         -- Quit the LLDB debugger.
  r         -- Launch the executable in the debugger.
  rbreak    -- Sets a breakpoint or set of breakpoints in the executable.
  repl      -- Evaluate an expression on the current thread.  Displays any
               returned value with LLDB's default formatting.
  run       -- Launch the executable in the debugger.
  s         -- Source level single step, stepping into calls.  Defaults to
               current thread unless specified.
  si        -- Instruction level single step, stepping into calls.  Defaults to
               current thread unless specified.
  sif       -- Step through the current block, stopping if you step directly
               into a function whose name matches the TargetFunctionName.
  step      -- Source level single step, stepping into calls.  Defaults to
               current thread unless specified.
  stepi     -- Instruction level single step, stepping into calls.  Defaults to
               current thread unless specified.
  t         -- Change the currently selected thread.
  tbreak    -- Set a one-shot breakpoint using one of several shorthand
               formats.
  undisplay -- Stop displaying expression at every stop (specified by stop-hook
               index.)
  up        -- Select an older stack frame.  Defaults to moving one frame, a
               numeric argument can specify an arbitrary number.
  x         -- Read from the memory of the current target process.
For more information on any command, type 'help <command-name>'.

看不到解释的话把这段英文Google 翻译一下就行了,建议大部分命令一个一个测试一下,以后需要使用的时候有影响.
下面介绍几个命令:
p - 基础数据类型打印

(lldb) p btn2.tag
(NSInteger) $2 = 0

call - 执行一段代码 比如

(lldb)  call 1+2+3 
(int) $1 = 6

bt - 显示当前线程的调用堆栈。bt all 显示所有线程堆栈信息。

(lldb) bt
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 2.1
  * frame #0: 0x00000001058e42bc ARKit-OC`-[ViewController viewDidLoad](self=0x00007f9031f0b580, _cmd="viewDidLoad") at ViewController.m:31
    frame #1: 0x0000000108ef88a5 UIKit`-[UIViewController loadViewIfRequired] + 1235 等等

q - 简单,就是退出断点
e - 设置常量,方便接下来调试用(注意: 声明和使用时对象名称前要加$):

(lldb) e NSArray *$testArray = @[@"A",@"B"]
(lldb) po $testArray[1]
B
(lldb) 

由于image跟崩溃调试有关,下面简单介绍一下image

image - Commands for accessing information for one or more target
modules.
image - 地址信息

 NSArray *TestArray = @[];
 NSLog(@"%@",TestArray[1]);//越界测试

一般项目开启全局断点,会自动打印崩溃信息及位置,如下:


设置全局断点

xcode底部日志窗口:


报错信息

如果不开启全局断点All Exceptions,就会打印下面日志:

*** First throw call stack:
(
    0   CoreFoundation                      0x00000001088591ab __exceptionPreprocess + 171
    1   libobjc.A.dylib                     0x0000000107c86f41 objc_exception_throw + 48
    2   CoreFoundation                      0x0000000108871f3d -[__NSArray0 objectAtIndex:] + 93
    3   ARKit-OC                            0x00000001073782a3 -[ViewController viewDidLoad] + 1571
    4   UIKit                               0x00000001094998a5 -[UIViewController loadViewIfRequired] + 1235
    5   UIKit                               0x00000001094e11ec -[UINavigationController _updateScrollViewFromViewController:toViewController:] + 68
    6   UIKit                               0x00000001094e1528 -[UINavigationController _startTransition:fromViewController:toViewController:] + 153
    7   UIKit                               0x00000001094e263f -[UINavigationController _startDeferredTransitionIfNeeded:] + 841
    8   UIKit                               0x00000001094e38c3 -[UINavigationController __viewWillLayoutSubviews] + 150
    9   UIKit                               0x000000010973ca49 -[UILayoutContainerView layoutSubviews] + 231
    10  UIKit                               0x00000001093c56f5 -[UIView(CALayerDelegate) layoutSublayersOfLayer:] + 1439
    11  QuartzCore                          0x000000010d88b3ee -[CALayer layoutSublayers] + 153
    12  QuartzCore                          0x000000010d88f4dd _ZN2CA5Layer16layout_if_neededEPNS_11TransactionE + 401
    13  QuartzCore                          0x000000010d817ded _ZN2CA7Context18commit_transactionEPNS_11TransactionE + 365
    14  QuartzCore                          0x000000010d843704 _ZN2CA11Transaction6commitEv + 500
    15  UIKit                               0x000000010930fd3a __34-[UIApplication _firstCommitBlock]_block_invoke_2 + 141
    16  CoreFoundation                      0x00000001087fc18c __CFRUNLOOP_IS_CALLING_OUT_TO_A_BLOCK__ + 12
    17  CoreFoundation                      0x00000001087e096b __CFRunLoopDoBlocks + 203
    18  CoreFoundation                      0x00000001087e0144 __CFRunLoopRun + 1300
    19  CoreFoundation                      0x00000001087df9b9 CFRunLoopRunSpecific + 409
    20  GraphicsServices                    0x00000001102c79c6 GSEventRunModal + 62
    21  UIKit                               0x00000001092f45e8 UIApplicationMain + 159
    22  ARKit-OC                            0x0000000107379f3f main + 111
    23  libdyld.dylib                       0x000000010c80dd81 start + 1
    24  ???                                 0x0000000000000001 0x0 + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException

看到这一堆日志新手可能有点蒙,其实这是记录崩溃前后信息,也就是从24 -> 0顺序执行的:
比如23行start开始 -> 22 行 执行main.m里的main函数 -> 等等

所以我们从0开始看,发现第2, 3行比较熟悉(2 objectAtIndex 一般是导致数组越界):
2 CoreFoundation 0x0000000108871f3d -[__NSArray0 objectAtIndex:] + 93
3 ARKit-OC 0x00000001073782a3 -[ViewController viewDidLoad] + 1571
依次是: 序号 项目名称 地址 执行的方法 数字

下面使用image查看该地址0x0000000108871f3d 和 0x00000001073782a3信息:
(lldb) image lookup --address 0x0000000108871f3d
      Address: CoreFoundation[0x0000000000110f3d] (CoreFoundation.__TEXT.__text + 1113661)
      Summary: CoreFoundation`-[__NSArray0 objectAtIndex:] + 93

(lldb) image lookup --address 0x00000001073782a3
      Address: ARKit-OC[0x00000001000022a3] (ARKit-OC.__TEXT.__text + 3459)
      Summary: ARKit-OC`-[ViewController viewDidLoad] + 1571 at ViewController.m:40
(lldb) 

显然最后一行:at ViewController.m:40 告诉我们崩溃位置.

(其他很多有用的命令自行百度或者Google)

三 : 条件执行断点:Edit Breakpoint

看截图:


Edit Breakpoint

弹出下面编辑框:


Edit Breakpoint编辑框

Condition:输入判断表达式,运行到此判断为true时触发断点
Ignore:设置一个值,比如4,前4次判断会被忽略,到第5次再触发断点
Action:触发断点后执行动作:


Action
Debugger Command
    AppleScript:执行一段脚本代码
    Capture GPU Frame:当前GPU绘制帧
    Debugger Command:lldb调试命令
    Log Message:打印信息
    Shell Command:选择shell命令文件,异步执行的
    Sound:播放音乐

[动手试试上面命令吧!]

四 : 全局断点模式设置


图片.png

(1) Swift Error breakpoint :Swift语言的断点
(2)Exception breakpoint: 全局断点(OC 和 C++语言)
(3)Symbolic breakpoint:符号断点
...

4.0 (1) Swift Error breakpoint :对应Swift语言的断点
4.1 下面介绍一下(2)Exception breakpoint: 全局断点
全局断点

(2.1) 断点语言:OC 和 C++,有时候出问题的代码在第三方或混编C代码,这个时候需要选择C++进行调试


断点语言

异常处理机制四个关键字:@try,@catch,@thorw,@finally。
1.当代码有可能出现异常时,我们把他放到@try语句块中。
2.@catch()块包含了处理@try块里的抛出的异常的逻辑。
3.如果直接使用@throw块来抛出异常,这个异常本质上是一个OC的对象。咱们可以使用NSException对象,但是不局限于他们。
4.无论异常是否发生,@finally块里面的语句都会执行。

异常处理机制
4.2 下面介绍一下(3)Symbolic breakpoint:符号断点

在Symbol一栏输入需要断点对应的方法


Symbolic

相关文章

网友评论

      本文标题:iOS 只会用NSLog误区,LLDB, Breakpoint调

      本文链接:https://www.haomeiwen.com/subject/gzgnvxtx.html