续之前的“
App再瘦身
”。
这个帖子整理我遇到过的iPhone App Crash 类型以及解决办法。Crash 原因有很多,不同技术所导致的Crash 会不同。整理出来的经验应该会相对片面,有错误的地方和任何问题,请毫不犹豫的指出。
保证App 持续稳定运行是非常必要的,开发人员应该把维护产品稳定性、提高产品性能意识融入到每次编写代码过程当中,这也是很多公司考察优秀开发人员的一个重要环节。
Crash 原因
Crash 原因有共性,归纳起来有:
• 内存管理错误
• 程序逻辑错误
• SDK 错误 (部署版本< 编译版本)
• 主线程阻塞
内存管理错误
内存管理是iPhone 开发所要掌握的最基本问题,特别是使用引用计数手动管理内存的情况。内存管理错误包括:
• 内存泄漏:未释放不会再使用对象。比如alloc 忘记release,malloc 忘记free 。可用XcodeProduct 菜单下的Analyze 功能来解决该问题;
• 引用出错:引用已经被释放的对象指针。很多“莫名其妙”的Crash 都是由于窗体经历的生命周期所导致的(viewDidUnload 、viewDidLoad ),在iOSSimulator 里模拟内存警告就可以解决该问题;
• 内存警告:App 使用的内存超出设备的限制,iOS 将强制挂起App ,强制挂起iOS 是不会记录Crashlog ,Flurry 也无法记录。内存泄漏、快速/ 大量的分配内存都可能导致内存警告,这时候应该尽可能的释放不需要的资源。通过Instruments->Allocations 里的Heapshot 功能能够找出哪些资源未被释放。
WWDC 2012 的Session242 - iOS App Performance_ Memory 是专门讨论内存管理这个话题。
程序逻辑错误
数组越界、堆栈溢出、并发操作、逻辑错误。扎实的编码基础、严谨细致的工作习惯、清晰的思路可以避免这类错误;
SDK错误
这个错误出现的现象是有的设备运行正常,有的会Crash 。原因是未找到框架、类、方法、属性。比如:用iOS5.0 SDK 编译并运行在iOS4.0 的设备上,5.0 的Twitter 框架在4.0 的设备上找不到。这种问题常出现在用苹果新发布的Xcode 编译原有的工程。
未找到框架的解决办法是:部署版本>= 编译版本。iOS 框架向后兼容做的很棒,部署版本> 编译版本一般不会出现问题。
未找到 类、方法、属性 的解决办法是: 先判断是否存在再使用
if(NSClassFromString(@"MFMailComposeViewController"))
respondsToSelector:
主线程阻塞
主线程阻塞超过10s ,iOS 将强制挂起App 。把长时间的任务放到后台线程去执行,可使用NSThread,NSOperation, dispatch 。WWDC2012 的Session235 - iOS App Performance_ Responsiveness 有详细的介绍。
解决 Crash
思路是:定位Crash 的程序代码,预测Crash 原因,寻找解决方案,测试。
有多种方式可以定位Crash 的程序代码:
• Debug 模式时,iOSSimulator 断点测试定位Crash 的堆栈;
• 真机连接iTunes 查看Crashlog (Debug 模式下) ;
• 通过Flurry 的错误记录查看;
定位之后,就是重新思考程序上下文逻辑,并有理由的预测Crash 出现的原因。预测的越多,理解的越深。
寻找解决方案的方法有:
• 浏览苹果官方SDK 文档,找出错误原因;
• Google 搜索Crash 输出的信息,重点查找行业内技术论坛:cocoachina 、stackoverflow 、iphonedevsdk 等;
• 查看历届WWDC 的视频、示例代码;
• 在工程里添加环境变量: NSZombieEnabled 、NSDebugEnabled ,输出有价值的信息;
• 如果未找到任何信息,可以寻求 苹果官方论坛 、业内技术论坛的帮助;
测试
找到解决方案后就需要测试,测试功能输入输出的准确性、程序性能、是否引入新的bug 。测试有专业的测试工程师来负责,但开发工程师不能依赖测试工程师来发现问题,尽量独立解决已知存在的问题。
由于Xcode 部署工程到真机上比较耗时间,如果可以的话尽可能用iOSSimulator 来测试,以减少测试的时间。
建议开发工程师有一个checklist ,在产品测试时自己逐一过一下上面常见的问题,这个能够避免大部分Crash 。下图是我们一个产品的FlurryError 记录,那120 个错误Session 是测试Crash 时留下的。当然这个记录是没有包括iOS 将强制挂起App 的情况。
这个帖子整理我遇到过的iPhone App Crash 类型以及解决办法。Crash 原因有很多,不同技术所导致的Crash 会不同。整理出来的经验应该会相对片面,有错误的地方和任何问题,请毫不犹豫的指出。
保证App 持续稳定运行是非常必要的,开发人员应该把维护产品稳定性、提高产品性能意识融入到每次编写代码过程当中,这也是很多公司考察优秀开发人员的一个重要环节。
Crash 原因
Crash 原因有共性,归纳起来有:
• 内存管理错误
• 程序逻辑错误
• SDK 错误 (部署版本< 编译版本)
• 主线程阻塞
内存管理错误
内存管理是iPhone 开发所要掌握的最基本问题,特别是使用引用计数手动管理内存的情况。内存管理错误包括:
• 内存泄漏:未释放不会再使用对象。比如alloc 忘记release,malloc 忘记free 。可用XcodeProduct 菜单下的Analyze 功能来解决该问题;
• 引用出错:引用已经被释放的对象指针。很多“莫名其妙”的Crash 都是由于窗体经历的生命周期所导致的(viewDidUnload 、viewDidLoad ),在iOSSimulator 里模拟内存警告就可以解决该问题;
• 内存警告:App 使用的内存超出设备的限制,iOS 将强制挂起App ,强制挂起iOS 是不会记录Crashlog ,Flurry 也无法记录。内存泄漏、快速/ 大量的分配内存都可能导致内存警告,这时候应该尽可能的释放不需要的资源。通过Instruments->Allocations 里的Heapshot 功能能够找出哪些资源未被释放。
WWDC 2012 的Session242 - iOS App Performance_ Memory 是专门讨论内存管理这个话题。
程序逻辑错误
数组越界、堆栈溢出、并发操作、逻辑错误。扎实的编码基础、严谨细致的工作习惯、清晰的思路可以避免这类错误;
SDK错误
这个错误出现的现象是有的设备运行正常,有的会Crash 。原因是未找到框架、类、方法、属性。比如:用iOS5.0 SDK 编译并运行在iOS4.0 的设备上,5.0 的Twitter 框架在4.0 的设备上找不到。这种问题常出现在用苹果新发布的Xcode 编译原有的工程。
未找到框架的解决办法是:部署版本>= 编译版本。iOS 框架向后兼容做的很棒,部署版本> 编译版本一般不会出现问题。
未找到 类、方法、属性 的解决办法是: 先判断是否存在再使用
if(NSClassFromString(@"MFMailComposeViewController"))
respondsToSelector:
主线程阻塞
主线程阻塞超过10s ,iOS 将强制挂起App 。把长时间的任务放到后台线程去执行,可使用NSThread,NSOperation, dispatch 。WWDC2012 的Session235 - iOS App Performance_ Responsiveness 有详细的介绍。
解决 Crash
思路是:定位Crash 的程序代码,预测Crash 原因,寻找解决方案,测试。
有多种方式可以定位Crash 的程序代码:
• Debug 模式时,iOSSimulator 断点测试定位Crash 的堆栈;
• 真机连接iTunes 查看Crashlog (Debug 模式下) ;
• 通过Flurry 的错误记录查看;
定位之后,就是重新思考程序上下文逻辑,并有理由的预测Crash 出现的原因。预测的越多,理解的越深。
寻找解决方案的方法有:
• 浏览苹果官方SDK 文档,找出错误原因;
• Google 搜索Crash 输出的信息,重点查找行业内技术论坛:cocoachina 、stackoverflow 、iphonedevsdk 等;
• 查看历届WWDC 的视频、示例代码;
• 在工程里添加环境变量: NSZombieEnabled 、NSDebugEnabled ,输出有价值的信息;
• 如果未找到任何信息,可以寻求 苹果官方论坛 、业内技术论坛的帮助;
测试
找到解决方案后就需要测试,测试功能输入输出的准确性、程序性能、是否引入新的bug 。测试有专业的测试工程师来负责,但开发工程师不能依赖测试工程师来发现问题,尽量独立解决已知存在的问题。
由于Xcode 部署工程到真机上比较耗时间,如果可以的话尽可能用iOSSimulator 来测试,以减少测试的时间。
建议开发工程师有一个checklist ,在产品测试时自己逐一过一下上面常见的问题,这个能够避免大部分Crash 。下图是我们一个产品的FlurryError 记录,那120 个错误Session 是测试Crash 时留下的。当然这个记录是没有包括iOS 将强制挂起App 的情况。