美文网首页
iOS开发之Xcode常用调试技巧总结

iOS开发之Xcode常用调试技巧总结

作者: sfandy | 来源:发表于2016-11-03 11:45 被阅读53次

    本文为投稿文章
    链接:http://www.yangshebing.com/2016/10/27/iOS开发之Xcode常用调试(Debug)技巧总结/

    一、Xcode调试技巧之:NSLog

    上面也提到了,在我们日常的开发过程中最常见的Debug方式就是打Log。而在OC语言中,打Log是采用NSLog方法。但是NSLog效率低下,具体原因可以看这篇博客(《NSLog效率低下的原因及尝试lldb断点打印Log》)。所以在平时的开发过程中,能不打Log就不打Log。实在想打Log网上也有对NSLog的一些优化方法,可以阅读王巍的《宏定义的黑魔法 - 宏菜鸟起飞手册》如下代码便出自其中:

    另外在使用NSLog的时候应当注意,release版本中应该要去掉NSLog。

    二、Xcode调试技巧之:LLDB

    1、po:print object的缩写,表示显示对象的文本描述,如果对象不存在则打印nil。

    简单的打印一个对象我们就不说了,我们来说说特殊的应用场景吧!

    应用场景:你想知道一个视图包含了哪些子视图。当然你可以循环打印子视图,但是下面只需要一个命令即可解决。

    输出视图层级关系(这是一个被隐藏的命令):po [[self view] recursiveDescription]

    还有个常见的调试场景,比如你要打印一个model。你直接用NSLog或po对象处理的结果是model的地址,这并不是我们想要的。怎么办?有没有解决方法呢?

    答案是有的。你可以重写model里面的description方法。但是,如果model里属性非常多,这样就不适用了。你不可能说在description方法里面拼接属性返回。这样不仅麻烦,而且可读性非常差。到这里,我们可以利用runtime动态获取属性并返回。不过我并不建议你重写description方法,我推荐你重写debugDescription方法(至于详细的介绍以及如何重写请点击此处),因为debugDescription方法和description方法效果一样,区别在于debugDescription方法是在你使用po命令时调用的,实际上也是调用了description方法。

    2、p:可以用来打印基本数据类型。

    3、call:执行一段代码

    call NSLog(@"%@", @"yang")

    4、expr:动态执行指定表达式

    expr i = 101
    输出:(int)$0 = 101

    5、bt:打印当前线程堆栈信息

    如果要打印所以线程堆栈信息,使用:bt all即可。

    6、image:常用来寻找栈地址对应代码位置:

    举个栗子:
    应用场景(数组越界)模拟代码:

    NSArray *array = @[@"yang",@"she",@"bing"];
    NSLog(@"%@",array[3]);

    错误信息如下:

    *** Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[__NSArrayI objectAtIndex:]: index 3 beyond bounds [0 .. 2]'
    *** First throw call stack:
    (
    0 CoreFoundation 0x000000010579734b __exceptionPreprocess + 171
    1 libobjc.A.dylib 0x00000001051f821e objc_exception_throw + 48
    2 CoreFoundation 0x00000001056d1eeb -[__NSArrayI objectAtIndex:] + 155
    3 BGMultimediaDemo 0x0000000104c25550 -[ViewController viewDidLoad] + 192
    4 UIKit 0x0000000105d5c06d -[UIViewController loadViewIfRequired] + 1258
    ......
    ......
    ......
    21 BGMultimediaDemo 0x0000000104c25adf main + 111
    22 libdyld.dylib 0x000000010857268d start + 1
    23 ??? 0x0000000000000001 0x0 + 1
    )
    libc++abi.dylib: terminating with uncaught exception of type NSException

    这个时候我们如果怀疑出错的地址是0x0000000104c25550,那么我们可以使用下面命令来找出错误代码的位置:

    image lookup --address 0x0000000104c25550

    执行命令后输出结果如下:

    Address: BGMultimediaDemo[0x0000000100001550] (BGMultimediaDemo.__TEXT.__text + 192)
    Summary: BGMultimediaDemo`-[ViewController viewDidLoad] + 192 at ViewController.m:30

    从上面输出结果中可以看出,错误位置应该是ViewController.m文件中的30行。是不是超级好用?反正我觉得好用。

    三、Xcode调试技巧之:断点(Breakpoint)
    断点就不多说了,相信基本上都知道。
    四、Xcode调试技巧之:EXC_BAD_ACCESS

    1、开启僵尸对象

    开启Zombie模式之后会导致内存上升,因为所以已经被释放(引用计数为0)的对象被僵尸对象取代,并未真的释放掉。这个时候再给僵尸对象发送消息,就会抛出异常,并打印出异常信息,你可以轻松的找到错误代码位置,结束Zombies时会释放。它的主要功能是检测野指针调用。

    使用方法:

    “Edit Scheme…” —> “Run” —> “Diagnostics” —> “Zombie Objects”
    打开”Edit Scheme…”窗口:

    开启Zombie模式:


    注意:Zombie模式不能再真机上使用,只能在模拟器上使用。

    2、Address Sanitizer(地址消毒剂)

    在Xcode7之后新增了AddressSanitizer工具,为我们调试EXC_BAD_ACCESS错误提供了便利。当程序创建变量分配一段内存时,将此内存后面的一段内存也冻结住,标识为中毒内存。程序访问到中毒内存时(访问越界),立即中断程序,抛出异常并打印异常信息。你可以根据中断位置及输出的Log信息来解决错误。当然,如果变量已经释放了,它所占用的内存也会被标识为中毒内存,这个时候访问这片内存空间同样会抛出异常。

    使用方法:
    “Edit Scheme…” —> “Run” —> “Diagnostics” —> “Zombie Objects”

    开启AddressSanitizer之后,在调试程序的过程中,如果有遇到EXC_BAD_ACCESS错误,程序则会自动终端,抛出异常。

    相关文章

      网友评论

          本文标题:iOS开发之Xcode常用调试技巧总结

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