我现在已经在编写iOS应用程序一段时间了。但是我的应用程序仍然经常崩溃,而且要花费很长时间才能使它们非常稳定。我觉得这非常令人恼火。
那么,关于编写抗崩溃的iOS应用程序,有哪些编程模式可以参考呢?
我现在已经在编写iOS应用程序一段时间了。但是我的应用程序仍然经常崩溃,而且要花费很长时间才能使它们非常稳定。我觉得这非常令人恼火。
那么,关于编写抗崩溃的iOS应用程序,有哪些编程模式可以参考呢?
1) 使用ARC。
ARC有一个小的学习曲线,我在SO上读到的最大问题是人们实例化对象但忘记将对象分配给强大的ivar(或属性),因此对象神秘地消失了。无论如何,好处是如此令人信服,你应该掌握它。当你这样做时,现在必须保持清晰的大部分内存管理问题都会消失。
2) 构建干净
构建时永远不应该有警告。如果你有一堆警告,当真正的问题出现时,它会被埋在你已经习惯忽略的废话中。专业程序员构建干净。
3) 使用分析器
Xcode/llvm有一个非常棒的分析器 - 使用它 - 它在产品菜单项下。然后清理每一个它给你的警告。
4) 使用正确的配置
我总是有一个发布(或分发)配置,一个ReleaseWithAsserts和Debug。只有在使用lldb时才使用Debug,因为代码要大得多,而且它将以不同于优化编译的方式执行。ReleaseWithAsserts类似于Debug,但Debug=1预处理器标志被删除,并将优化器设置为-Os(默认为Release)。
最后,发布/分发配置在预处理宏中包含以下内容:
NS_BLOCK_ASSERTIONS=1 NDEBUG
第一个关闭所有 'NSAssert()' 行,第二个关闭所有 'assert()' 语句。这样,在您发布的代码中就没有任何断言是活动的。
5) 大量使用断言。
断言是程序员最好的朋友之一。我在这里看到了很多问题,如果程序员只使用它们,这些问题将永远不会被写出来。它们的开销在于输入它们,因为(在我的用法中)它们在发布配置中被编译掉了。
每当您从另一个源获取对象时,请断言其存在(即:
MyObject *foo = [self someMethod];
assert(foo);
这个很容易打,但当一个空对象在数千条指令之后引起问题时,它可以节省你数小时的调试时间。你也可以对类进行断言:
MyObject *foo = [self someMethod];
assert([foo isMemberOfClass:[MyObject class]]);
当你从字典中提取对象时,这非常有用。
您可以在方法开头放置断言,以验证您收到的对象不是nil。
您可以断言某些变量具有值:
assert(i>1 && i<5);
除了发布/分发配置之外,在所有配置中,assert语句都是“活动的”,但在该配置中它们被编译掉。
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中清除任何通知观察者。