【iOS】bug调试技巧
文章目录
- 【iOS】bug调试技巧
- 前言
- 断点(Breakpoint)
- Exception Breakpoint
- Symbolic Breakpoint
- Constraint Error Breakpoint & Test Failure Breakpoint
- 断点编辑
- 设置观察点
- LLDB (Low Level Debugger)
- 打印对象和标量
- Zombie Objects
- Memory Graph
- 小结
前言
在写知乎日报这个项目的过程中我遇到了各式各样的一个bug,一个bug对于一个项目而言往往是非常致命的,我们有时候会因为一个小bug苦苦寻找20,30分钟,然后发现是一个简单的问题,所以笔者为此特地学习了有关于iOS开发中bug调试的内容。
断点(Breakpoint)
断点可以用来暂停程序运行,实时查看符号和对象。Xcode 支持多种不同类型的断点。例如:异常断点、符号断点等。下面就来介绍一些断点的使用场景。
Exception Breakpoint
我们在平常的项目中经常会出现下图的一个报错情况:
这里是一个数组越界的问题,但是却出现在了一个主函数中,很显然这种情况并不方便我们去定位我们的一个代码的问题,在一个项目中找到这种小问题,会非常麻烦,这里我们只需要三个步骤就可以让我们快速的找到报错的一个位置。
第一个步骤就是找到位于项目左侧的这个按钮:
然后找到项目左下角的一个添加按钮:
点击添加按钮后,点击Exception Breakpoint这个地方,然后我们就添加了一个断点,这个断点可以帮助我们快速的找到问题的所在。
下面看效果图:
可以看到我们的程序停在了数组越界的地方,这样是不是比之前自己主动去寻找数组越界的地方方便的多,然后这里一般情况是看不到控制台的一个打印信息的,
上面抛出异常时控制台是没有对应的错误信息输出的。下面介绍一个小技巧,在异常断点里面加一个 LLDB 命令:po $arg1
。因为 objc_exception_throw
第一个参数就是异常信息本身,所以控制台就会打印出该异常对象。按照下图设置就可以了
这时候我们就可以在控制台看到报错的信息了
Symbolic Breakpoint
符号断点会在特定的某一个方法上打上断点,然后让程序停止在我们告知他的一个方法上。
设置的方法同样是和之前一样。
设置好符号断点后需要进行编辑,在 Symbol 填入符号,符号有以下几种:
- 方法名,其会暂停所有该符号的调用。例如:
removeFromSuperview
,只要调用了removeFromSuperview
就会暂停程序执行 - 类的一个方法。例如:
-[MyView1 removeFromSuperview]
- C 函数。例如:
c_func
如图示方法添加即可:
这里笔者其实还不是很清楚这个断点在什么场合中使用,这里笔者引用一段话:
符号断点可以在一些复杂业务和探索系统调用系统调用&zhida_source=entity)的场景下起到重要作用。例如有个 UIView 视图有多处对其进行了
removeFromSuperview
调用。如果你想了解其所有移除场景。那么你需要一个符号断点来协助你。这里有个注意的点就是在该类中必须有对应的方法实现。例如:-[MyView1 removeFromSuperview]
就需要在MyView1
中重写removeFromSuperview
方法,否则无法进入该符号断点。本人就利用过符号断点解决过一个videoView
被误移除的 Bug。引用自:iOS-调试技巧
Constraint Error Breakpoint & Test Failure Breakpoint
笔者自己也没怎么使用过这两个断点,所以笔者直接引用一段话
这两种断点在实际开发当中使用的比较少。下面就简单介绍下其作用
Constraint Error Breakpoint
:是一个自动布局约束错误断点,其可以帮你快速定位自动布局错误;Test Failure Breakpoint
:是一个单元测试UI测试失败断点,当测试失败时会直接暂时程序,其可以帮你快速定位测试失败原因。引用自:iOS-调试技巧
断点编辑
在很多情况中,我们往往不需要让某一个代码每次都停下,我们往往只需要一个条件下的一个某一个变量的情况,所以这时候断点编辑就有了他自己的一个意义,我们可以设置条件让这段代码在某些情况下停下,而且也可以自定义打印的一个信息,如下图所示,我们在一段代码的i == 2
的情况下打上了断点
最后可以看到一个选项,这个选项的含义是可以让程序继续运行,这时候我们其实就可以有一个想法也就是我们是不是可以用断点来代替我们的NSLog
的输出,他其实就可以实现这样的一个效果,笔者的控制台就会输出下文的内容:
这里来看笔者的一段实践操作,这里笔者给我们的y那一行代码打上了断点
然后给断点设置如下的一个打印信息的方式:
最后我们这里就实现了一个NSLog的一个效果,也就是我们这段代码里面没有任何的NSLog却可以把我们的一个Y全部打印出来:
设置观察点
观察点可以在某个变量中保存的值发生变化时暂停程序的执行。观察点可帮助解决与全局变量 / 单例对象有关的问题,追踪具体是哪个方法改变了特定的全局变量。此外,不能在程序未运行时添加观察点,必须在进入调试状态时在变量观察窗口进行观察点设置。设置方法如下图:
LLDB (Low Level Debugger)
LLDB 是 Xcode 内置动态调试工具。在程序进入断点时,Xcode 的调试控制台就会进入 LLDB 命令行调试状态。这里介绍一下一些简单的调试命令:
打印对象和标量
LLDB 最常用的命令就是 po (print object)
, 意为打印对象。po 可以打印当前作用域下的所有变量。例如:
(lldb) po self
如果你需要打印一些标量(非对象)时,此时要用 p
,而不是 po
。例如:
(lldb) p (CGRect) self.view.bounds
(lldb) p (NSUInteger) self.myNumber
使用 po 还可以直接改变程序运行中的变量值。例如:self.myNumber = 10
(lldb) po self.myNumber = 10
Zombie Objects
- Zombie Objects 一种用来检测内存错误(
EXC_BAD_ACCESS
)的对象,它可以捕获任何对尝试访问坏内存的调用。 - 如果给 Zombie Objects 发送消息时,那么将在运行期间崩溃和输出错误日志。通过日志可以定位野指针对象调用的方法和类名。
开启方式:Product -> Scheme -> Edit Scheme -> Diagnostics -> Zombie Objects
。
这些内容笔者还没用到,之后如果有用到再详细补充他的一个学习的内容。
Memory Graph
Memory Graph
这个东西可以帮我们查找和修复被废弃的内存,它有点类似于 View Hierarchy,它可以很方便的查看对象的引用关系如果该对象存在一个内存泄漏,则该对象会被加上一个感叹好
我们可以看到如下图形:
小结
笔者简单介绍了一下iOS开发中调试的一个内容,这里也只是简单介绍了一下有哪些内容以及调试手段有什么,之后如何调试自己的项目其实主要还是看自己对于这些调试功能的熟练程度。笔者这篇文章也是初学调试的内容,如果有什么问题还请不吝指出。
参考博客:
- iOS-调试技巧