这个帖子整理我遇到过的
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 的情况。
保证 App 持续稳定运行是非常必要的,开发人员应该把维护产品稳定性、提高产品性能意识融入到每次编写代码过程当中,这也是很多公司考察优秀开发人员的一个重要环节。
Crash 原因
Crash 原因有共性,归纳起来有:
• 内存管理错误
• 程序逻辑错误
• SDK 错误 (部署版本 < 编译版本)
• 主线程阻塞
内存管理错误
内存管理是 iPhone 开发所要掌握的最基本问题,特别是使用引用计数手动管理内存的情况。内存管理错误包括:
• 内存泄漏:未释放不会再使用对象。比如 alloc 忘记 release,malloc 忘记 free 。可用 XcodeProduct 菜单下的 Analyze 功能来解决该问题;
• 引用出错:引用已经被释放的对象指针。很多“莫名其妙”的 Crash 都是由于窗体经历的生命周期所导致的( viewDidUnload 、 viewDidLoad ),在 iOSSimulator 里模拟内存警告就可以解决该问题;
![](http://oriole2.com/Upload/CocoachinaImages/AppStability_1.png)
• 内存警告: App 使用的内存超出设备的限制, iOS 将强制挂起 App ,强制挂起 iOS 是不会记录 Crashlog , Flurry 也无法记录。内存泄漏、快速 / 大量的分配内存都可能导致内存警告,这时候应该尽可能的释放不需要的资源。通过 Instruments->Allocations 里的 Heapshot 功能能够找出哪些资源未被释放。
![](http://oriole2.com/Upload/CocoachinaImages/AppStability_2.png)
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 的情况。