iphone开发中一个让小弟我纠结到深夜的Bug

iphone开发中一个让我纠结到深夜的Bug

    程序员的悲催莫过于测试人员通告有P0的bug, 更悲催的是告诉你的时候已经到下班时间而且准备冻结产品代码的那一刻。

    上一个iPhone项目我就遇到这种悲催的事情, 下午六点多, 在经历了一天的杀虫大战, 把前面测试报的P0,P1P2的bug全部一个一个干掉后, 漫长的产品开发也进入尾声。 就等着评估小组的评估报告,然后收拾东西走人。 熟料一个P0的bug赫然出现在那张清单里。

     细细一看, 其实还是很熟悉。 因为之前测试也报过一次, 被我以不能重现给打回去了。 Bug描述很简单, 就是程序用着用着一个页面上突然会出现完全空白的列表。 这种莫名其妙的Bug在紧张的开发实现功能的阶段肯定没功夫细究的。因为一个开发这不能重现的Bug, 基本上没有修复的可能性。 就算我说修复了,如何验证也是个大问题。

     只有现象, 没有重现步骤的Bug 在开发过程中绝对不少见。 而且处理方式大多跟我之前的一样, 直接打回去。 但是到了产品即将上线, 被评估人员也找出来了就不是小问题了。 因为评估人员不熟悉我们的产品, 就当自己是一个用户在使用它。 这意味着用户最终也会有很大概率碰到同样的场景。   

   之前工作的三四年中天天跟Bug打交道, 自认为是一个杀虫高手。 这种关键时刻当然得把杀手锏给亮出来。由于不能重现, 也就意味着调试的意义不大。 唯一能做的可能是认真审核每一条语句。 而自己写的代码总有一些先入为主的想法, 我赶紧找了一个对这个功能的代码逻辑之前没有过任何理解的同事开始对这段代码进行细致的评审, 这样他可以用怀疑一切的态度来审视这段代码, 希望他能找到任何蛛丝马迹。 测试人员也开始对这个页面进行反复的随即测试,力求能再次重现。虽然可能找不到重现步骤,但是给她分发一个开发电脑后,调试器能挂在这个进程上面,还是能重日志中找出点什么东西。 我自己则把这段代码删除, 对其进行重构,重写。 

   两个小时过去了, 我的代码重构完, 但测试人员和帮我评审代码的同事却都没有找到任何问题。 我只能寄希望于我重构后的代码已经悄悄的把这个Bug修复掉了。赶紧把代码提交上去, 然后分发到多个设备上, 测试开发人员一起上都来帮忙测试这块功能。 一票人测了半个小时, 这个Bug貌似被消灭了。 可就在我们准备宣布胜利的时候, 一个同事突然说这个现象在他的手机上又重现了。God, 赶紧跑过去看。 现象还是那么诡异,界面上的列表是空的。可惜他的手机没连调试器。 我在这台重现好的机器上, 尝试了一下于这个页面的其他的功能, 却发现了更诡异的现象。 界面是空的, 但是与它相关的功能里却能从里面取到数据。我反复的查看代码,UI上是空的意味着绝对没有数据在这块,代码逻辑没出任何问题, 可为什么又能拿到数据呢?

   在耗费无数脑细胞后, 终于想到一种可能, 就是这里出现了两个相同的界面, 一个空白的把一个有数据的给覆盖了。 iPhone开发的界面是用Interface builder做的xib文件,当系统内存吃紧的情况下,没有展示在当前的xib作为资源文件是会被回收的, 这就是viewcontroller里面的 viewDidLoad 和 viewDidUnload. 我再检查了下我的viewDidload, 果然有一个潜在的隐患, 我把几个scrollView对象给存在了一个NSDictionary 里面。 并且如果Dictionary 变量不会重新的构造赋值, 如果不为空的话。而Dictionary 对保存的对象是强引用的, 加入真的发生我所猜测的内存紧张, xib里的对象释放时, 这几个对象引用不能降到0达不到释放的目的。 而假如程序重新回到这个页面, xib重新加载, 新构造的对象又不会重新复制到我用到的这个Dictionary. 也就是说它存的是带了的老的界面对象, 而新的真正用户看到的界面对象却没在Dictionary里面, 它们也就不会重新加载数据。 于是赶紧拿模拟器来模拟了一个内存吃紧的场景验证我的这个猜想。 果然重现了这个Bug. 有重现步骤后, 修复就变得简单了。 但是它却引出了另外一个问题, 为什么会再程序跑了一段时间后,偶然出现。 直觉告诉我是某个功能有内存泄露, 在重复某些操作后,内存吃紧回到我这个页面就导致了上述的Bug. 赶忙把Xcode自带的那个内存泄露检测工具拿出来帮忙检查内存泄露, 果然在一个同事的一个段代码里发现了严重的内存泄露。把这些修复完,已经深夜了。

     因为整个产品代码是由几个人一起写的, 其中有一个同事是刚工作几个月没有太多的代码经验, 功能实现了, 可里面却埋下了不少的炸弹。 之后又陆续收到其他人员报过来的一些开发过程中被掩盖的问题,欠的债要还, 埋的坑总是要填的。 等坑填的差不多了,已经是第二天早晨5点多, 天都亮了。

    这是一个很大的教训, 工作前期没有重视测试报过来的每一个BUG, 代码没有严格的按照苹果推荐的方式去写, 内存泄露检查没有提前做, 没有利用好手中的模拟器和开发辅助程序对代码进行更细致的检查,没有定期的做代码评审, 这些看似开发中省时间的方法, 总是会让你在后期以加倍的时间给补回来。 这些都是以后开发中要注意的东西。