不管是在大型的C项目中, 还是在现在的iOS项目中, 调试一直是伴随学习和解决问题的关键武器. 通过调试可以让你理解一个对象或者一个过程的本质. 逐步接触到作者设计的核心.
通过娴熟的调试技巧, 你也可以快速定位到bug的位置. 从而快速的解决问题.
话不多说. 现在罗列一些个人在iOS项目中经常使用的调试技巧.
- po 命令
po命令是经常使用的打印对象的命令. 例如"po tableView".
但是, 对象不仅仅局限于对象名称, 还可以是指针, 有时我们在调试一个问题时, 获取到了对象指针, 但是当前上下文没有指针指向的对象的引用. 那么这时候就可以"po 0x12345678"这样使用了.
po 的延伸用法还有"p intVar", "p structVar", "p *(id)object" , 这条命令可以打印对象的结构体.
po 命令还有一个重要用途: 那就是在程序运行时临时,额外地执行代码块. 例如, 服务器返回了一个数据, 在断点处, 发现这个数据有问题, 我需要更改字典的一个key value对, 那么此时你可以在控制台使用po [oneDic setValue: forKey:]. 这样就可以避免再次重新运行程序. 在反复调试某个bug时, 这样可以节省大量时间. 但是, 为什么这个命令可以这么用呢? 其实这可以归结到po命令的一个弊端. 那就是它可以改变内存数据. 这个在某些地方是不允许的, 因为大多数我们不想调试的时候改变运行时数据.
- bt 命令
调试的另一个目的就是掌握代码块的调用逻辑. 同一个代码快可以在多个线程中, 多个方法中被重复调用. 那么如何确定某个语句在被调用时所处的上下文呢? 通过在断点位置中加入bt命令, 就可以输出当前语句被执行时当前线程的上下文.
这个命令在一般断点下没有用途, 调用堆栈可以直接从Xcode中读出来. 但是, 你可以在"条件断点"中加入该命令, 然后让条件断点自动继续执行. 这样通过控制台就可以阅读哪些模块, 哪些线程, 哪个对象, 到底在什么时候调用了该语句? 这个在调试基础服务的bug时非常之有用.
更多的bt命令可以参考LLVM官网.
- 符号断点
某个时候, 同事很忙, 你不想去问他"诶, 你这个页面的ViewController是哪个来着?", "诶, 你这个button的响应方法在哪里来着?".
也有可能, 在某个时候, 在你的页面push完过后, 发现状态栏怎么突然被隐藏了, 你很想知道这到底是谁搞的鬼? 你想把它揪出来, 然后和某某当面对峙, "看又是你做的坏事.测试又提我bug了."
在上面的情况中, 符号断点就可以发挥巨大的作用.
对于C函数, 不需要加"()"
对于定位button的响应方法, 需要在运行时函数objc_msgSend中加入断点. 还需要2次"继续运行", 具体步骤读者可以自己实践.
对于找出状态栏隐藏的方法, 和第一个问题的解决方法类似.
总之, 符号断点类似与VC2008的数据断点. 本质是在没有源代码可供插入断点的情况下, 插入断点.
这次先总结这么多. 如有兴趣, 请继续关注此分类.
其实生活好比一个庞大且复杂的程序, 每个人都是程序的一个代码快, 没有一个人的代码是完美无缺的, 每个人的能力, 每个人的风格都不一致. 为了满足自己的需求, 我们需要不断的修正别人不正确的程序所带来的困扰. 不断使自己的代码块更加健壮. 当我们有了调试的武器, 好比知道了解决各种的问题的基本方法. 通过这个方法, 我们就可以使自己的生活更加趋向于完美.
生活, 就是一个不断学习, 并解决问题的过程. 调试(方法论), 就是你的有力武器.