【发布时间】:2012-08-13 23:00:49
【问题描述】:
我现在正在编写 ios 应用程序一段时间。但是我的应用程序仍然经常崩溃,并且需要时间才能使它们非常稳定。我觉得这很烦人。
那么,有没有关于防崩溃编程 iOS 应用程序的编程模式?
【问题讨论】:
-
使用 Xcode 分析功能,启用 Zombie Objects,使用 Instruments。
标签: ios design-patterns crash
我现在正在编写 ios 应用程序一段时间。但是我的应用程序仍然经常崩溃,并且需要时间才能使它们非常稳定。我觉得这很烦人。
那么,有没有关于防崩溃编程 iOS 应用程序的编程模式?
【问题讨论】:
标签: ios design-patterns crash
【讨论】:
1) 使用 ARC。
ARC 的学习曲线很小,我在 SO 上读到的一个大问题是人们实例化对象但忘记将对象分配给强 ivar(或属性),因此对象神秘地消失了。无论如何,好处是如此引人注目,您应该掌握这一点。当您这样做时,您必须立即保留的大部分内存管理内容都会消失。
2) 构建干净
您在构建时永远不应该出现警告。如果你有一堆,当一个真正的问题出现时,它就会被你习惯于忽略的垃圾线埋没。专业程序员构建干净。
3) 使用分析
Xcode/llvm 有一个非凡的分析器 - 使用它 - 它位于 Product 菜单项下。然后清理它给你的每一个警告。
4) 使用正确的配置
我总是有一个发布(或分发)配置、一个 ReleaseWithAsserts 和一个调试。我只在使用 lldb 时使用 Debug,因为代码要大得多,并且它的执行方式与优化的编译方式不同。 ReleaseWithAsserts 与 Debug 类似,但去掉了 Debug=1 预处理器标志,并将优化器设置为 -Os(Release 的默认值)。
最后,Release/Distribution 配置在 Preprocessing Macros 中有以下内容:
NS_BLOCK_ASSERTIONS=1 NDEBUG
第一个关闭所有“NSAssert()”行,第二个关闭所有“assert()”语句。这样,您的交付代码中就没有任何断言处于活动状态
5) 使用大量的断言。
断言是作为程序员可以拥有的最好的朋友之一。我在这里看到了很多问题,如果程序员只使用它们就永远不会写出来。开销在于键入它们,因为(在我的使用中)它们在发布配置中被编译掉。
每当你从另一个来源获得一个对象时,断言它的存在(即:
MyObject *foo = [self someMethod];
assert(foo);
这很容易输入,但是当一个 nil 对象在数千条指令之后导致问题时,可以节省您数小时的调试时间。你也可以在类上断言:
MyObject *foo = [self someMethod];
assert([foo isMemberOfClass:[MyObject class]]);
这在您从字典中提取对象时特别有用。
您可以将断言放在方法的开头,以验证您收到的对象也不是 nil。
你可以断言某个变量有一个值:
assert(i>1 && i<5);
同样,除了 Release/Distribution 配置,断言是“实时的”,但在该配置中它们被编译出来。
NSAssert 类似 - 但您必须根据参数的数量使用不同的宏。
NSAssert(foo, @"Foo was nil");
NSAssert1(foo, @"Foo was nil, and i=%d", i);
...
6) 使用选择性日志来确保应该发生的事情是
您可以定义自己的日志宏,该宏会被编译出来用于发布/分发。将此添加到您的 pch 文件中:
#ifndef NDEBUG
#define MYLog NSLog
#else
#define MYLog(format, ...)
#endif
这指出了另一点 - 你可以使用:
#ifndef NDEBUG
...
#endif
屏蔽一些执行更复杂检查的代码 - 它只对您的开发构建有效,而不是用于发布/分发。
【讨论】:
你可能已经做了这些,但这是我做的:
使用调试器/模拟器转到应用程序中的每个屏幕,然后选择“模拟内存警告”。返回上一个屏幕。这会导致 viewDidLoad 中现有的 UIView 对象和变量分配被重新分配(这可能导致错误的指针引用)。
确保在 dealloc 中使所有正在运行的计时器无效。
如果对象 A 已将自己设为对象 B 的委托,请确保在对象 A 的 dealloc 中将其清除。
确保清除 dealloc 中的所有通知观察者。
【讨论】: