iOS调试进阶-更高效的使用Xcode和LLDB

你是否苦恼于每次改完 Bug 都要从新运行来验证结果?你是否苦恼于修改 UI 问题不能所见即所得?你是否苦恼于修改一个小问题而要屡次等待从新编译运行的时间?如今,经过对本篇文章的学习,不只能够解决你的苦恼,还能够提高你的 Debug 能力,使你再也不局限于只利用断点使用p/po来打印的变量的值。express

如下是本文的主要内容:bash

  • 修改简单的逻辑 - expression
  • 跳过不想执行的语句 - thread jump
  • 经过 Debug 修改 UI - recursiveDescription

废话很少说,让咱们开始吧!app

expression 的使用

在咱们平常开发中,常常会碰到一些某些特定状况下出现 Bug 的问题,好比下面这段代码:框架

// Bug: 减操做错误,应该减一
if isAdd {
    count = count + 1
} else {
    count = count - 2
}
countLabel.text = "\(count)"
复制代码

代码说明:ide

isAdd 是一个布尔值,咱们经过这个布尔值来对count进行相应操做。
正常的需求是:若是isAdd是true咱们则对count进行加一操做;
若是isAdd是false咱们则对count进行减一的操做。
复制代码

如今根据上下文isAdd的值为true,假如咱们要测试为false的状况,咱们可能会在项目中手动将isAdd设为false在从新运行项目验证修改的结果。那么咱们如何在不用从新运行项目的状况下修改isAdd的值呢?答案就是 expression 了。post

expression 有两种使用方式:学习

  • 在 LLDB 中输入:每次都要输入
  • 在断点中配置:只需输入一次

在 LLDB 中的使用

在断点中的配置

下面是具体操做流程:测试

  • if isAdd {这行代码打一个断
  • 右键断点选择 edit Breakpoint
  • 点击弹出框的 Action 按钮,在下方的文本框输入expression isAdd = false
  • 选中 optional 选项

再进行相关操做,就看见 if 语句执行的是 else 的分支了,同理你也能够将count = count - 1设置为表达式来验证结果。ui

plus:编辑过的断点会在箭头内部添加一个白色三角形,具体可见上方的两个图的区别。这样可使咱们更方便的找到已经编辑过的断点。spa

thread jump 的使用

当咱们想跳过一行代码的时候咱们可使用这个命令,当咱们使用的时候,Xcode 会弹出一个警告,告诉咱们这种作法很危险。因此,咱们使用的时候要确保不会出现问题再使用。

具体使用与上面的步骤相似,惟一的不一样就是把上面的命令替换为thread jump --by 1。该命令的1就是跳过1行的意思,咱们能够根据具体需求修改此值。

修改 UI

下面介绍一种很是实用的命令,那就是使用断点来调试 UI 问题。在平常开发中,咱们会常常微调一些 UI 样式,每次修改再从新编译运行是很是浪费时间的,咱们能够经过 LLDB 来实现改完不运行便可看见效果。

好比咱们想要修改self.view的某个子控件的位置,咱们可使用下面的命令来打印出self.view的全部子控件的详细信息。

//格式:expression -l objc -O -- <expr>
// - 打印self.view 的子视图
expression -l objc -O -- [`self.view` recursiveDescription]
复制代码

经过上面的命令咱们能够拿到须要修改控件的内存地址,而后再用下面的命令来修改子控件的 frame :

//格式: unsafeBitCast(point, to: type)
//第一个参数为子控件的内存地址,第二个参数为子控件的类型。

// - 将一个UIButton的实例的x赋值为100
expression unsafeBitCast(0x7fa94cb015c0, to: UIButton.self).frame.origin.x = 100
复制代码

将子控件的内存地址修改以后,咱们能够经过如下命令来刷新暂存区,看见实际的效果,而不是经过从新运行。

//刷新暂缓区 
expression CATransaction.flush()
复制代码

Note - 设置别名

上面的命令很长,咱们每次都这么输入很麻烦,咱们能够也能够设置别名来使用。

//设置别名
commend alias 别名 原命令
//这样就可使用 flush 来代替 expression CATransaction.flush()
command alias flush expression -l objc -- (void)[CATransaction flush]
复制代码

p po frame

p/po: 无实质性的区别,看你本身须要的格式使用。
frame: 直接从内存中获取,输出 LLDB 的格式。
复制代码
  • p/po 不能使用的时候,frame应该能使用
  • 在Xcode10.2 中,新添加了v/vo来替代p/po,具体详情可参见这里

总结

  • LLDB 表达式能够修改代码的状态
  • 经过thread jump --by 1跳过代码
  • 使用 Obj-c 的代码在 Swift 的框架中:expression -l objc -O -- <expr>
  • 刷新视图暂存区:CATransaction.flush()
  • 设置别名:
command alias poc expression -l objc -O --
command alias flush expression -l objc -- (void)[CATransaction flush]
复制代码

参考

相关文章
相关标签/搜索