iOS 开发调试技巧
对于软件开发而言,调试是必须学会的技能,重要性不言而喻。对于调试的技能,基本上是可以迁移的,也就是说你以前在其他平台上掌握的很多调试技巧,很多也是可以用在iOS开发中。不同语言、不同IDE、不同平台的调试,有同性也有个性。今天我们就来学习一下iOS开发中的调试技巧,语言暂用为OC,IDE当然是强大的Xcode。首先说明下,Xcode已经为我们调试项目提供了极大的方便。
【1.普通断点】
断点(Breakpoint)绝对是调试程序的第一大选择,也是掌握的基础技能。顾名思义,当程序运行到断点处时会暂停运行。比如断点打在11行,那么程序就会停在11行(注意:程序只运行到了前10行,第11行其实还没有被执行!!!)。只要在代码行旁边点击,就能添加一个断点,再次点击,就能让断点不可用(disable了,仍然存在,只是不起作用了)。在某一行创建断点的快捷键是:command+\


并能在调试过程中在下方看到参数的值:

【2.条件断点】
以上的断点只是最普通的,我们还能对断点的属性进行配置,设置条件,使断点更加智能化,右键断点进入编辑对话框:

我以一个循环作为测试代码:

循环中的代码每次都要单步执行,可能这并不是我想要的。我想要在i为3的时候中断程序,进行调试,编写条件如下:

设置i==3的条件后,程序就会在该条件时中断,而不会每次到达该位置都中断。中断时输出如下:

同时也可以设置Ignore参数,会忽略前面n次的断点运行,会在第n+1次中断。

调试输出如下:

同时,还可以查看某个函数被调用的次数,设置Action参数如下,注意要选中Automatically continue after evaluating actions.

输出结果如下:

【3.异常断点】
断点的功能不限于上面所述。开发iOS知道,如果我们因为异常然后程序crash了,代码就直接跑到main.m的main函数中去了。为什么就不能跑到出现异常的代码中呢???异常断点就为我们解决该问题,程序就会在异常出现的那行代码终止。创建异常断点图例如下:

如下所示就创建完成了。如果碰到异常crash时,尝试使用异常断点吧。

【4.符号断点Symbolic Breakpoint】
符号断点的创建也同异常断点。一般符号断点可以在你指定的[类名 方法名]时中断执行。

配置符号断点如下:可以当执行到ViewController类的viewDidLoad方法时中断执行。

如果你的Symbol只写了一个函数名,那么就会在出现该函数名的地方就中断执行。如下,就会在运行到doAnimation的时候中断。是不是很强大呢?


【5.Analyze分析器】
Analyze分析器是一种静态的工具,可以对我们的程序进行分析,找出我们未使用的变量,或一些死存储。执行Analyze如下:Product-->Analyze. 如下蓝色的标记就是静态分析的结果。


当然,我们可以设置在编译程序的时候同时Analyze,把下列选项设为Yes即可。

【6.Profile检查器】
这个工具实在是太NB了,三言两语说不完,贴张图,大家感受一下,我会在以后的博客中慢慢讲解该工具的使用。同样在Product-->Profile中打开。

【7.僵尸对象】
iOS中把那些已经release但还没完全消失的对象叫做僵尸对象,对已经release的对象再次释放,就会发生异常。虽然自从使用ARC后,由于对象释放产生的异常已经大大变少,但偶尔还会出现。开启僵尸对象模式后,就能快速定位到异常位置。开启方式如下:Product-->Scheme-->Edit Scheme. 勾选Enable Zombie Objects即可。

【8.lldb命令】
Xcode中使用llvm编译器,公认为最好的C、C++、OC、Swift编译器。而lldb是llvm中的调试器,我们可以使用一些简单的命令进行调试,我还是把上面的循环代码作为测试代码。

断点调试中,使用po命令、print命令在Console控制台打印出变量信息:

【9.NSLog打印】
应该说NSLog打印信息是初学者最喜欢的调试手法,也是最简单的调试,通过打印出的信息查看程序运行的路径。但是打印出的信息较少,本身NSLog效率较低,有人使用宏做了部分优化,代码如下:能够打印出所在类名、所在方法名、详细时间、行号。
- #import "ViewController.h"
- #define NSLog(format, ...) do { \
- fprintf(stderr, " %s\n", \
- [[[NSString stringWithUTF8String:__FILE__] lastPathComponent] UTF8String], \
- __LINE__, __func__); \
- (NSLog)((format), ##__VA_ARGS__); \
- fprintf(stderr, "-------\n"); \
- } while ()
- @interface ViewController ()
- @end
- @implementation ViewController
- - (void)viewDidLoad {
- [super viewDidLoad];
- for (int i = ; i < ; i++) {
- NSLog(@"我的值:%d",i);
- }
- }
- @end
打印结果如下:

【10.生命周期方法init,dealloc】
对于ViewController来说,有两个生命周期函数我们可以进行重写,也就是init和dealloc方法。对于某些对象的状态,我们可以在这两个方法中查看。尤其是在dealloc中可以看到当ViewController退出的时候某个对象是否release。
- - (instancetype)init
- {
- self = [super init];
- if (self) {
- //初始化语句;
- }
- return self;
- }
- - (void)dealloc
- {
- //释放后调用;
- }
【11.查看代码运行时间】
有时候我们想要准确的知道某段代码、某个循环执行的时间,然后分析效率等问题,这个时候就需要执行时间是多少。正好看到网上已经有人做了这个工作,我就直接摘下来了。正好也用了宏的方式计算时间,我们只要在需要计算时间的代码块前后写上TICK,TOCK宏即可。当然,原理也是非常的简单,也就是使用NSDate计算差值。
- #import "ViewController.h"
- #define TICK NSDate *startTime = [NSDate date]
- #define TOCK NSLog(@"Time: %f", -[startTime timeIntervalSinceNow])
- @interface ViewController ()
- @end
- @implementation ViewController
- - (void)viewDidLoad {
- [super viewDidLoad];
- TICK;
- for (int i = ; i < ; i++) {
- NSLog(@"我的值:%d",i);
- }
- TOCK;
- }
- @end
打印结果如下:

【12.手机截屏】
手机截屏也算调试?哈哈。其实也算是开发中的一个小技巧哈。其实大家都会在iPhone上同时按电源键+Home键截屏,然后使用各种通讯软件发给其他人,这个略显不方便。我们来使用Xcode中的方式截屏。当手机接上电脑后,注意要把调试设备选为自己的手机:

然后选择Debug-->View Debugging-->Take Screenshot... .然后可以看到手机屏幕已经在你的电脑桌面了。是不是比直接在手机上操作方便多了呢?这样就可以快速的发给其他开发者、PM等人了。
【13.viewDidLoad不建议写太多代码】
个人建议不要在viewDidLoad方法中写入太多代码。尤其是涉及该界面中的动画的时候,因为执行viewDidLoad方法的时候,界面可能还没完全加载出来,如果此时把动画放在viewDidLoad中,可能会造成动画无法显示。当然也不建议把耗时的网络请求和动画效果都放在viewDidLoad中,界面的阻塞也会造成动画无法显示。可以尝试把动画放在viewDidAppear,viewWillAppear方法中。对于这类涉及UI的问题,调试也是比较麻烦的。。。
【14.视图调试】
如今iOS开发的UI设计有很多种方式,比如storyboard,xib,代码实现。对于stoayboard,xib可视化实现是比较简单的,但是对于一些“iOS老程序员”而言,都喜欢使用代码实现UI,并且可能UI层次还比较复杂。这样就给我们新接手项目的开发者带来很多困扰。如何快速查看一个复杂UI的界面层次和布局,最快的方法就是用到视图调试。
当项目运行到某一个界面(可以是模拟器或真机)时,开启视图调试,点击按钮如图:

这样就会进入试图调试,你可以很方便的查看这个界面。这里可以看到控件之间的层次关系。

左侧的树形层次图可以在查看线程、队列和UI之间切换:

【15】常用的编译宏定义:可以让代码在不同的编译情况下执行。
(1)__OPTIMIZE__ :用于release和debug的判断,当选择了__OPTIMIZE__ 时,可以让代码在release时执行,在debug时不执行。示例如下:
#ifndef __OPTIMIZE__
//这里执行的是debug模式下
else
//这里执行的是release模式下
#endif
(2)__i386__ 与 __x86_64__ :用于模拟器环境和真机环境的判断。满足该条件的代码只在模拟器下执行。示例代码如下:
#if defined (__i386__) || defined (__x86_64__)
//模拟器下执行
#else
//真机下执行
#endif
(3)__IPHONE_OS_VERSION_MAX_ALLOWED :当前编译的SDK版本,可以与__IPHONE_9_0等宏定义进行比较,进行不同版本下代码的执行。示例如下:
if (__IPHONE_OS_VERSION_MAX_ALLOWED == __IPHONE_9_0) {
//如果当前SDK版本为9.0是执行这里的代码
}else{
//否则执行这里
}
【16】预编译宏 #ifdef #else #endif
#ifdef ****
//代码1
else
//代码2
#endif
意思是 如果标识符****已被#define命令定义过,则对代码1进行编译,否则对代码2进行编译。
同时也有#ifndef,则与#ifdef刚好相反。
总结
很好用的技巧
iOS 开发调试技巧的更多相关文章
- iOS开发调试技巧总结(持续更新中)
作者:乞力马扎罗的雪 原文 对于软件开发而言,调试是必须学会的技能,重要性不言而喻.对于调试的技能,基本上是可以迁移的,也就是说你以前在其他平台上掌握的很多调试技巧,很多也是可以用在iOS开发中.不 ...
- iOS开发实用技巧—在手机浏览器头部弹出app应用下载提示
iOS开发实用技巧—在手机浏览器头部弹出app应用下载提示 本文介绍其简单使用: 第一步:在本地建立一个访问的服务端. 打开本地终端,在本地新建一个文件夹,在该文件夹中存放测试的html页面. ...
- iOS开发实用技巧—Objective-C中的各种遍历(迭代)方式
iOS开发实用技巧—Objective-C中的各种遍历(迭代)方式 说明: 1)该文简短介绍在iOS开发中遍历字典.数组和集合的几种常见方式. 2)该文对应的代码可以在下面的地址获得:https:// ...
- iOS开发实用技巧—项目新特性页面的处理
iOS开发实用技巧篇—项目新特性页面的处理 说明:本文主要说明在项目开发中会涉及到的最最简单的新特性界面(实用UIScrollView展示多张图片的轮播)的处理. 代码示例: 新建一个专门的处理新特性 ...
- 10个Visual Studio原生开发调试技巧
10个Visual Studio原生开发调试技巧(1) 2013-05-29 13:30 佚名 开源中国 我要评论(1) 字号:T | T 以下的列表中你可以看到写原生开发的调试技巧(接着以前的文章来 ...
- Linux c c++ 开发调试技巧
看到一篇介绍 linux c/c++ 开发调试技巧的文章,感觉挺使用,哪来和大家分享. 通向 UNIX 天堂的 10 个阶梯Author: Arpan Sen, 高级技术人员, Systems Doc ...
- iOS开发小技巧 - UILabel添加中划线
iOS开发小技巧 遇到的问题: 给Label添加中划线,然后并没有效果 NSString *str = [NSString stringWithFormat:@"合计金额 ¥%.2f&quo ...
- iOS开发小技巧 - runtime适配字体
iOS开发小技巧 - runtime适配字体 版权声明:本文为博主原创文章,未经博主允许不得转载,有问题可联系博主Email: liuyongjiesail@icloud.com 一个iOS开发项目无 ...
- iOS开发--常用技巧 (MJRefresh详解)
iOS开发--常用技巧 (MJRefresh详解) https://github.com/CoderMJLee/MJRefresh 下拉刷新01-默认 self.tableView.head ...
随机推荐
- linux 从命令行自动识别文件并将其打开的命令
若是shell是 zsh,则可: 使用 alias -s 定义后缀别名 (zsh) % alias -s pl=perl % script.pl perl script.pl % alias -s p ...
- MySQL 5.5 服务器变量详解一(转)
add by zhj:在MySQL5.6中对一些参数有增删改,详见http://dev.mysql.com/doc/refman/5.6/en/server-system-variables.html ...
- C#UDP同步实例
差不多有一个礼拜总算有点进步. 代码很简单,只是为了实现功能. 网络上的资源是很多,除了不能用的,就是抄来抄去,是在乏味浪费时间. 说一下代码背景:实现的功能是发送端发送消息,接收端接收后立即响应,发 ...
- kindeditor html代码过滤不能保存
这是因为编辑器默认开启了过滤模式(filterMode:true).当filterMode为true时,编辑器会根据htmlTags设定自动过滤HTML代码,主要是为了生成干净的代码.如果想保留所有H ...
- C#上位机读数据库
string connectionString = string.Format("server=(local);uid=sa;pwd=1234567890;database=msp430&q ...
- CSS学习篇核心之——盒子模型
概述 关于CSS的一些基础知识我们在前面文章中已经有所了解,这篇文章我们主要来学习下CSS中的核心知识盒子模型的知识. 盒子模型 元素框的最内部分是实际的内容(element),直接包围内容的是内边距 ...
- 用ILMerge.exe合并dll
F:\ILMerge>ILMerge /targetplatform:v4,"C:\WINDOWS\Microsoft.NET\Framework\v4.0.30319" / ...
- 消息系统Kafka介绍 - 董的博客
1. 概述 Kafka是Linkedin于2010年12月份开源的消息系统,它主要用于处理活跃的流式数据.活跃的流式数据在web网站应用中非常常见,这些数据包括网站的pv.用户访问了什么内容,搜索了 ...
- ADO与ADO.NET的区别
ADO是使用ole db接口并基于微软的COM技术,ADO.NET使用自己的ADO.NET接口并基于微软的.NET体系架构,所以ADO.NET与ADO是两种数据访问方式. ADO以recordset存 ...
- log4.net
1 简介 1.1Log4net的优点: 几乎所有的大型应用都会有自己的用于跟踪调试的API.因为一旦程序被部署以后,就不太可能再利用专门的调试工具了.然而一个管理员可能需要有一套强大的日志系统 ...