iOS开发之Xcode常用调试技巧总结
转载自:iOS开发之Xcode常用调试技巧总结
最近在面试,面试过程中问到了一些Xcode常用的调试技巧问题。平常开发过程中用的还挺顺手的,但你要突然让我说,确实一脸懵逼。Debug的技巧很多,比如最常见的方式是打个Log,在一些工程中处处可见NSLog。还有就是打断点的Debug方式等。诸如此类,下面就自己在开发过程中常用的Xcode调试技巧简单的做个总结。
一、Xcode调试技巧之:NSLog
上面也提到了,在我们日常的开发过程中最常见的Debug方式就是打Log。而在OC语言中,打Log是采用NSLog方法。但是NSLog效率低下,具体原因可以看这篇博客(《NSLog效率低下的原因及尝试lldb断点打印Log》)。所以在平时的开发过程中,能不打Log就不打Log。实在想打Log网上也有对NSLog的一些优化方法,可以阅读王巍的《宏定义的黑魔法 - 宏菜鸟起飞手册》如下代码便出自其中:
1 #define NSLog(format, ...) do { \ 2 fprintf(stderr, " %s\n", \ 3 [[[NSString stringWithUTF8String:__FILE__] lastPathComponent] UTF8String], \ 4 __LINE__, __func__); \ 5 (NSLog)((format), ##__VA_ARGS__); \ 6 fprintf(stderr, "-------\n"); \ 7 } while (0)
另外在使用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:常用来寻找栈地址对应代码位置:
举个栗子:
应用场景(数组越界)模拟代码:
1 NSArray *array = @[@"yang",@"she",@"bing"]; 2 NSLog(@"%@",array[3]);
错误信息如下:
1 *** Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[__NSArrayI objectAtIndex:]: index 3 beyond bounds [0 .. 2]' 2 *** First throw call stack: 3 ( 4 0 CoreFoundation 0x000000010579734b __exceptionPreprocess + 171 5 1 libobjc.A.dylib 0x00000001051f821e objc_exception_throw + 48 6 2 CoreFoundation 0x00000001056d1eeb -[__NSArrayI objectAtIndex:] + 155 7 3 BGMultimediaDemo 0x0000000104c25550 -[ViewController viewDidLoad] + 192 8 4 UIKit 0x0000000105d5c06d -[UIViewController loadViewIfRequired] + 1258 9 ...... 10 ...... 11 ...... 12 21 BGMultimediaDemo 0x0000000104c25adf main + 111 13 22 libdyld.dylib 0x000000010857268d start + 1 14 23 ??? 0x0000000000000001 0x0 + 1 15 ) 16 libc++abi.dylib: terminating with uncaught exception of type NSException
这个时候我们如果怀疑出错的地址是0x0000000104c25550,那么我们可以使用下面命令来找出错误代码的位置:
1 image lookup --address 0x0000000104c25550
执行命令后输出结果如下:
1 Address: BGMultimediaDemo[0x0000000100001550] (BGMultimediaDemo.__TEXT.__text + 192) 2 3 Summary: BGMultimediaDemo`-[ViewController viewDidLoad] + 192 at ViewController.m:30
从上面输出结果中可以看出,错误位置应该是ViewController.m文件中的30行。是不是超级好用?反正我觉得好用。
三、Xcode调试技巧之:断点(Breakpoint)
断点,程序员Debug必备技之一。
1、条件断点
打上断点之后,对断点进行编辑,设置相应过滤条件。下面简单的介绍一下条件设置:
Condition:返回一个布尔值,当布尔值为真触发断点,一般里面我们可以写一个表达式。
Ignore:忽略前N次断点,到N+1次再触发断点。
Action:断点触发事件,分为六种:
AppleScript:执行脚本。
Capture GPU Frame:用于OpenGL ES调试,捕获断点处GPU当前绘制帧。
Debugger Command:和控制台中输入LLDB调试命令一致。
Log Message:输出自定义格式信息至控制台。
Shell Command:接收命令文件及相应参数列表,Shell Command是异步执行的,只有勾选“Wait until done”才会等待Shell命令执行完在执行调试。
Sound:断点触发时播放声音。
这些功能平时在调试程序的过程中都可以进行尝试,说实话我用的设置Condition项会较多些。
Options(Automatically continue after evaluating actions选项):选中后,表示断点不会终止程序的运行。
2、异常断点
异常断点可以快速定位不满足特定条件的异常,比如常见的数组越界,这时候很难通过异常信息定位到错误所在位置。这个时候异常断点就可以发挥作用了。
添加异常断点:
编辑异常断点:
Exception:可以选择抛出异常对象类型:OC或C++。
Break:选择断点接收的抛出异常来源是Throw还是Catch语句。
3、符号断点
符号断点的创建方式和异常断点一样一样的,在符号断点中可以指定要中断执行的方法:
举个例子,常见的场景,我想让它执行到ViewController类中的viewWillAppear方法就中断执行:
Symbol:[ViewController viewWillAppear:]即[类名 方法名]可以执行到指定类的指定方法中开始断点。如果只有viewWillAppear:即方法名,它会执行到所以类中的viewWillAppear:方法中开始断点。
四、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开发过程中比较常见的一部分Debug方式。其他的还有比如说:Profile,Analyze分析,View Hierarchy(在调试视图显示异常时用的比较多)等,有兴趣的可以自行了解。
转载于:https://www.cnblogs.com/mukekeheart/p/7976661.html
iOS开发之Xcode常用调试技巧总结相关推荐
- (0025)iOS 开发之Xcode常用快捷键
Xcode常用快捷键 文档与帮助:Command + Shift +0(ZERO) 显示代码提示菜单:Esc 代码格式化:选中后 Ctrl + i 移动光标至本行行首:Ctrl + A 移动光标至本行 ...
- (0028)iOS 开发之Xcode使用技巧
1. 断点使用 快速查看一个函数的调用次数,且不添加一句代码. 如下图 这种方法适合于一个if方法,一个for循环,而且不会中断程序,且不用加一句代码.但是一定要选中下面的automatically ...
- (0043) iOS 开发之Xcode相关路径
Xcode 常用用路径: 1. 插件路径: ~/Library/Application Support/Developer/Shared/Xcode/Plug-ins 2. 模拟器app路径: ~/L ...
- (0099)iOS开发之Xcode编译工程报错问题汇总
1-/Target Support Files/Pods-SNFaceDetectDemo/Pods-SNFaceDetectDemo-frameworks.sh: No such file or d ...
- (0107)iOS开发之UI实时调试InjectionIII的使用
AppStore : 下载:Injectionlll 下载地址 使用步骤: 1.设置InjectionIII 打开InjectionIII工具,选择Open Project,选择你的代码所在的路径,然 ...
- (0103)iOS开发之Xcode 10 Error:Multiple commands produce问题及解决方案
问题描述 从Github 上Down下来的demo,用Xcode(10.1)打开,Build一下报如下错误: Showing All Messages :-1: Multiple commands p ...
- (0038) iOS 开发之Xcode下的DerivedData文件
Xcode下的DerivedData文件 长时间没清理:吃了大量硬盘.删除了之后,运行:CleanMyMac 竟然有50G啊!清除,爽啊! 一大早就跑过来删除xcode的垃圾文件,如果你很久没有删除x ...
- iOS开发之Runtime常用示例总结
深度好文,转载自:https://github.com/lizelu/ObjCRuntimeDemo 经常有小伙伴私下在Q上问一些关于Runtime的东西,问我有没有Runtime的相关博客,之前还真 ...
- iOS开发之TextView常用属性
基本属性: //textView尺寸和位置let textViewWidth: CGFloat = 223let textViewHeight: CGFloat = 198let textViewTo ...
最新文章
- Linux操作系统无人值守安装配置指南
- rhel6下组建两台主机的HA集群
- ROS初级教程1---官方ROS文件系统导览
- python解析树_如何使用python中的stanford解析器获取树的叶子?
- python 之 XML的基本应用总结
- 前端学习(1429):ajax封装四
- 5分钟掌握var,let和const异同
- PHP安装imagemagick扩展imagick
- VS2010链接SQLsever2008数据库时出现[DBNETLIB][ConnectionOpen (Connect()).]SQL Server 不存在或拒
- 数据库路由中间件MyCat - 源代码篇(11)
- adadelta算法_ADADELTA: AN ADAPTIVE LEARNING RATE METHOD(2012)
- 20180329整理巡检系统代码
- Ubuntu常用C语言IDE,Ubuntu下常用IDE的安装
- java list转map_List转Map的三种方法
- Vmware 8里运行冒险岛097——提取Vmware Tools源文件
- Java 8计算两个日期之间的月份
- 计算机成绩排名公式,职称计算机考试:Excel的数据分析—排位与百分比
- WIN7任务栏里面无用的图标如何清除
- 学习笔记——day09(抽象final接口)
- 英雄杀小程序微信区分服务器吗,小程序英雄杀挑战模式怎么玩
热门文章
- 项目架构中遇到需考虑的问题
- 定义项目名称快速启动项目
- 分数加减法 http://acm.nyist.net/JudgeOnline/problem.php?pid=111
- U盘怎么拔?该设备正在使用中,请关闭可能使用该设备的所有程序或窗口
- bigdicmal除法精度设置_java中BigDecimal进行加减乘除的基本用法
- pyplot 画多个图时搅合到了一起_这些认数字游戏,宝宝最喜欢,家长可以和宝宝一起玩...
- sm750显卡驱动linux版,M.2接口也能做显卡,慧荣科技提供图形显示芯片支持
- 3-24Pytorch与张量变形
- Java让数据库执行一条sql_java数据库编程——执行SQL 语句
- html 自定义属性_重学前端基础:属性操作,重点getAttribute / setAttribute方法