27
2017
09

系列:iOS开发-如何快速定位bug并解决

系列:iOS开发-快速定位bug并解决

本来没有打算针对这个开文的,

昨天工作忙完,闲来无事的时候,逛逛论坛,贴吧啥的,偶然间就发现了有人发bug帖.
http://www.jianshu.com/p/b51ead39c55d

上面说的神乎其神呢…
大家可以去看看.

怀着好奇的态度,下载了源码
干净的很,任何代码都没有
只有sotryboard 拖拽了几个控件, 绑定了present和dismiss的事件而已,除此以外没有任何代码
类似这样
这里写图片描述

于是编译运行项目
按照他说的,确实出现了这个小而且偏的bug复现

于是想要解决bug

  • 解决bug第一步

首先不管理内存什么的问题,怀疑是不是vc没有释放?
于是在vc的dealloc中添加打印


-(void)dealloc{ NSLog(@"%s",__FUNCTION__); } 

运行.返现没有任何问题,vc能够正常释放,但是textField确实没有被释放.排除vc引用

  • 解决bug第二步
    关闭bug描述中所说的第一个关键条件
    这里写图片描述

编译运行,发现bug已经没有复现了,项目运行正常,vc能够释放,textField也能够释放.所以下定解决,出现bug的原因就是这个属性了.

  • 解决bug第三步
    既然关闭了该属性,就能解决bug,那么bug肯定是这个属性导致的,
    于是考虑能否使用手写的方式.于是在vc中给这些小控件命名, 且手动设置该属性
    这里写图片描述

编译运行,bug复现,说明该属性在iOS11下确实会强引用控件,导致不能释放,

  • 解决bug第四步
    既然强引用导致的释放问题,那么调整引用时机即可, 这里能想到的是使用弱指针,或者其他弱引用打破强引用即可
    思路一,使用block来打破,这里因为UITextField没有相关的block方法,添加方法也没有什么意思,放弃
    思路二,使用UITextField的代理,因为使用过代理的开发者都知道,其实weak属性,所以其已经打破了强引用的条件,我们只需在适当的代理方法中设置即可
    于是添加代理
    这里写图片描述

代理完毕之后,找到合适的地方写需要的代码即可
这里写图片描述
遍历代理方法,发现这三个方法应该都是可以使用的,于是选择第一条,在准备编辑的时候便开始设置相关属性,于一开始就设置应该是一样的效果,完全不影响之前的效果
于是添加代码

-(BOOL)textFieldShouldBeginEditing:(UITextField *)textField{
    if (textField == self.psdTextField) {
        textField.secureTextEntry = YES;
    } else {
        textField.secureTextEntry = NO;
    }
    return YES;
}

再次编译运行,
bug已经不见了释放问题得到解决.

  • 解决bug第五步
    为了防止会再次出现其他莫名bug,需要设置一些通用的设置,比如界面释放结束编辑,vc释放前释放代理等
- (IBAction)back:(id)sender {
    [self.view endEditing:YES];
    [self dismissViewControllerAnimated:YES completion:nil];
}

所以整个bug修复的过程就是取消storyboard的secureTextEntry属性,改为手动添加,防止强引用,改为到代理里面设置,让系统自动帮我们打破强引用即可.

bug修复demo
https://github.com/spicyShrimp/iOS11_UITextField_Fix

其实这是一个很简单的bug修复问题
所以这个问题其实引出了我们作为iOS开发如何能快速定位bug的问题
在我们开发的时候,我们会经常出现各种莫名的bug,而自己却不能够定位,找不到思路,其实对于bug定位这个是一个技巧和经验的问题

大家都知道的方式有,打断点,逐行判断,打印log,判断是否正确输出…
经验在丰富一点的会使用控制台来po一些属性的值…
这些基本上每一个开发者都天天在用.

但是并不是这些就能完全的解决bug了
解决bug不是一味的出现bug,并且明确了bug发生的地方才能解决,很多bug是系统本事遗留导致
比如,我上篇博文说的文件索引在XCode9中的问题导致的bug就和代码完全无关
比如,上面提到的bug,小而偏,完全无法定位bug出现在哪一行
比如,我昨晚帮网友解决的一个响应链关系的bug,视图层次都是正确的,但是就是没有响应事件,网友却认为是子控件本身的bug导致,却没有换个思路,想到关于图层结构,是否可以响应事件,等基本常见bug,(最终问题也是出在的这里,图层window的问题,这里不赘述了)

所以这里我简单的总结一些解决bug的经验,分享给大家,希望大家都没有bug,

  1. 多打印log—-log能够最简单直接的反应很多东西,比如属性的值,比如对象的类是否正确…..
    这里写图片描述
  2. 多添加关键断点—-类似于log,我们每一个有问题的bug,大部分都是有复现路径的,我们需要逐步分析这个复现路径,就需要对每一个关键点添加断点,逐一排除即可修复
    这里写图片描述
  3. 学会使用异常断点等高级方式
    当我们无法明确某些复现路径的时候,我们可以通过异常断点来破获问题出现的地方
    这里写图片描述
    关于使用方法,大家可以自行网上学习一下,即可
  4. 学会使用po命令—- 添加断点,出现异常或者中断之后,对于没有log的信息,我们可以使用po命令来获取.
    这里写图片描述
  5. 学会使用其他工具,工具很多,这里不做介绍,比如instrument等.这些工具的掌握对于解决bug是很有帮助的
    这里写图片描述
  6. 使用crash日志—我们可以使用本地保存crash日志,也可以使用一些三方的bug收集SDK进行接入,比如bugly等,其可以在一定程度上定位到bug出错的位置,帮助我们解决
  7. 分析bug出现关键因素,对于上述还是无法定位bug的,我们需要自行分析bug出现的关键因素,不要放过任何一个细节,比如找不到某某方法,那就是要么没有引用文件,要么没有添加到项目,要么没有实现方法,要么编译器没有找到索引路径等.再比如上面的bug问题,关键点就是一个属性导致,我们在定位bug初期就应该能够想到,但是很多人却会忽略它
  8. 使用一些不同的思路去打破bug路径,这个是经验的问题,很多bug,使用普通的思路无法解决,可能是系统私有化,可能是时间拿不到,可能是其他一些因素无法控制,此时就需要经验了,如何能够改变思维,改变固有想法去绕过bug,也是需要掌握的,大家可以参考我的另一篇博客 ——( iOS11 导航栏按钮位置问题的解决 http://blog.csdn.net/spicyShrimp/article/details/77891717)
    对应很多因为系统限制的原因,无法使用正常思维解决的,我们就要另辟蹊径,至于如何做,这里只能说,熟能生巧
  9. 多积累基础知识,很多bug出现的因素并不是必然的,往往都是开发者的不严谨的逻辑造成的,所以算法的优劣,思路的清晰能够帮助我们减少很多bug,但是bug出现也不要担心,解决一次,就增长了一份记录,我们只要记录下来,下次就会自行很快的解决了,学习的路径有很多,论坛,书籍,视频,交流等..我们都不应该放过
  10. 对于每一个iOS或者Xcode的升级(其他开发工具或者开发环境也一样),如果可以,尽早的去适应和学习新的不同点,及早的思考某些API的改变会对我们的开发造成什么影响,做到提早预防

其实,能否对bug的快速定位,也间接反映了你的能力水平
希望大家在开发的时候永远没有bug….

欢迎访问我的系列博客
系列:iOS开发-前言+大纲
http://blog.csdn.net/spicyShrimp/article/details/62218521

上一篇:DataBinding的基本使用 下一篇:GIT 使用教程-廖雪峰