XCode调试技巧

tubiebutu 2019-06-20

本文从以前做的幻灯中整理而来的,主要讲一下XCode结合LLDB调试命令以及OBJC运行时的调试技巧。

一、常用宏定义

1、OPTIMIZE,Debug和Release判定

  • Release编译时定义
  • 当我们想要某些代码只在Debug环境下才运行可以使用此宏定义判别

    XCode调试技巧

2、i386x86_64,模拟器环境判定

  • 模拟器编译时定义
  • 有时工程依赖的Lib库只编译了真机的代码,模拟器编译出错。为了可以模拟器调试,使用此宏略过不能编译的代码

    XCode调试技巧

3、__IPHONE_8_0等,编译SDK的判定

  • SDK中会声明当前SDK版本定义,并且保留过往SDK版本定义
  • 有时我们编写的代码可能不会在最新的SDK编译,旧版本SDK编译会有潜在问题。使用此判定针对新老SDK版本分别编写代码
  • __IPHONE_OS_VERSION_MAX_ALLOWED,此宏定义声明了当前编译的SDK版本,可进行比较

    XCode调试技巧

4、使用-D编译器选项为编译Target追加宏定义

  • 在工程Target的Other C Flags项目中定义
  • 同一份代码可能由于证书、渠道、UI的不同,会建立多个Target分别进行打包。通过编译时追加宏定义,可在运行时判定Target。
  • 下例中定义了一个宏XDTarget,其值为800100。
  • 每一个Target可为XDTarget定义不同的值,这样运行时就可以判别Target,也免去了手工修改的麻烦。

    XCode调试技巧

5、NOP,空语句

  • C语言中有nop()函数,表示一条空语句。OC中没有提供。
  • 可以设计一个宏进行代替,用于挂载条件断点调试使用。

    XCode调试技巧

二、常用调试命令

1、PO,输出对象信息

  • po调用NSObject的description方法打印对象
  • po 变量名
  • po 内存地址
  • po 可返回对象的表达式
  • 如果对象没有被释放,PO会输出内容,否则只输出一个代表野指针的数字。根据此特性可在循环引用检查中判定对象是否被正常释放。
  • 配合表达式进行复杂查询

2、P,输出变量的值

  • p (类型)表达式
  • 除了值类型,也可以直接打印结构体数据

    XCode调试技巧

3、Call,执行一段代码

  • call (返回类型)表达式
  • 调试状态下,对于点语法支持不佳。如果发现符号未找到的情况,尝试使用发送消息的方式。如果还不行,根据提示,声明类型。对于PO、P等指令同样也需要注意

    XCode调试技巧

  • 可以修改值。

  • gdb下可以使用set实现,但lldb下set语法含义变化了,用call替代set指令
  • 配合NOP与断点,可以在运行时动态的控制程序的运行状态

    XCode调试技巧

  • 可以执行一段代码

    XCode调试技巧

    XCode调试技巧

4、bt,打印调用栈

XCode调试技巧

三、断点的使用技巧

1、一个断点可以做些什么事情?

XCode调试技巧

  • 可以加入一个条件,当满足此条件时触发断点。
  • 或者当执行某些次后才会触发
  • 可以执行若干种类的action

    XCode调试技巧

  • 当经过此断点时,执行action但是不会中断程序

    XCode调试技巧

    XCode调试技巧

2、异常断点

  • 某些crash是由程序抛出的异常导致的,比如数组越界。可以通过添加异常断点监控异常抛出的位置。

    XCode调试技巧

3、符号断点

  • 当符号对应的方法被调用时,中断
  • -/+[类 方法]
  • 举个例子:当UIViewController被载入时触发,并将当前的调用栈输出

    XCode调试技巧

4、内存断点

  • 当该块内存被调用时中断
  • 可通过XCode调试界面简化指令添加

    XCode调试技巧

  • 添加时,需要预先打断,找到要监视的内存地址(注意,地址每次启动都会失效)

  • 可以输出值的变化。可以找出内存是何时被修改的,值是如何变化的。

    XCode调试技巧

四、灵活的使用调试手段

以上这些调试手段虽然看起来比较简单,但只要灵活运用,就可以为调试带来很多便利和可能性。
比如下面一个例子

XCode调试技巧


图中有三个变量a,b,c。只要在NOP语句加入一个执行call命令的条件断点,通过调节断点的开闭,就可以在程序运行时动态的控制a,b,c的数值。这使得不用编写调试代码,就可以模拟各个状态,动态的调试程序分支。

此外,当程序发生异常时,一般是通过控制台报错信息,被动的定位问题所在。如果使用调试命令结合OBJC的运行时,可以主动的获知发生异常的状态。在MRC开发的时代,对于多次释放对象的问题,甚至可以一定程度的将僵尸对象还原回原始的对象,从而定位问题所在。

所以只要灵活的运用上面这些调试手段,相信您也会很快成为一个调试高手。

相关推荐

APCDE / 0评论 2019-12-01
野生的世界 / 0评论 2015-10-29