问题:app点击重新登陆有时候会闪退
1.初步定位
关注登录vc和登陆成功跳转vc两个界面代码,这里简称LoginVC和ShowVC。
ShowVC里面有3个childVC,这里分别简称childVC1,childVC2,childVC3。
在可疑地方大致下断点,重复调试了十几次,bug重现,此时控制台log日记为:
*** ASIHTTPRequest 0x7f8fe3b34110 went went isFinished=YES without being started by the queue it is in
大致意思是指这个网络请求任务在队列里面,但是没有开始就被取消了。在一个 operation 进入队列前不可被取消,也就是说:在 [NSOperation start] 被调用之前,[NSOperation isCancelled] 函数的返回值不能是YES。
所以初期的想法是找到这个0x7f8fe3b34110的NSOperation,简称这个NSOperation为可疑operation吧,然后判断它的状态,如果是已经取消的就不要放进队列。将这两个界面的ASIHTTPRequest任务设置断点打印,找到可疑operation,在加入队列前进行判断,如果NSOperation.isCancelled为NO才加入队列。找了半天,发现这个可疑operation是在childVC1里面执行的。
但是还是没有解决为题,报一样的错误日记。想了一下退出登陆的时候握取消全部任务,但是队列没有销毁,取消任务有延时,再次登录的时候有队列又开始执行任务,就会继续报错。所以尝试了operation取消成功后,再将重新登录的任务加入队列,过程比较繁琐,并且还是一样崩溃了,错误日记还是一样。
2.再次定位
将childVC1里面和这个可疑operation有关的代码注释,嘿,正常了不崩溃了。是这个可疑operation的原因。再将注释打开,运行一遍,bug重现了,此时Xcode给的提示是
EXC_BAD_ACCESS(code=EXC_I386_GPFLT)
访问了坏内存,使用了不存在的对象的错误。使用僵尸对象进行调试,Product -> Edit Scheme ->NSZombieEnabled打勾。
运行一遍此时控制台日志为
*** -[childVC1 Retain]:message sent to deallocated instance 0x7f8fe3b2xxxx
在ShowVC找到0x7f8fe3b2xxxx的childVC1,先不让childVC1释放,强行持有
在ShowVC创建childVC1的时候
ChildVC1*childVC1 = [[ChildVC1 alloc]init];
[self addChildViewController:childVC1];
self.childVC1= childVC1;
//关键
CFRetain((__bridgeCFTypeRef)(self.childVC1));
至此,问题解决
总结:对EXC_BAD_ACCESS这个错误果断采取NSZombieEnabled调试。
如有什么不对的地方,望各位大神指教