是否应该在生产iOS应用中留下断言?

时间:2011-12-12 21:52:11

标签: ios iphone assert

通常的做法可能是在应用程序开发期间将断言放入代码中以检查输入参数,数据完整性等。

我测试我的应用程序,但是,鉴于我不是Knuth(并且写了1美元的支票),而且我不能雇用一大群全职QA人员作为做一些医疗和太空系统软件公司,我认为所有的应用程序总会有很多在测试或质量保证期间从未见过的错误。假设在其他方面似乎非常不诚实。因此,在测试应用程序(并显然删除导致任何先前看到的ASSERT失败的所有错误)并准备好将应用程序发送给Apple之后,应该对发布/分发构建中的所有ASSERT检查做些什么?离开还是不做?

以下是将它们留在其中的一个理由:如果某个应用对某些用户行为不合适,该应用可能会被这些用户评为1星,而且没有人告诉开发人员为什么会有足够的细节。但是如果应用程序因ASSERT故障而崩溃,那么应用程序可能仍然会被评为1星级,但是如果有足够多的用户选择进入,开发人员可能通过iTunes和iTunes Connect间接获得一些故障转储,以找出问题所在。如果苹果公司因全新的ASSERT崩溃而被Apple拒绝,这将阻止应用程序的不良版本进入客户的设备。

4 个答案:

答案 0 :(得分:11)

完全按照您指定的原因保留它们,但也因为在某些情况下它们充当注释(特别是在Objective-C中涉及类型的情况)。并且不要担心性能损失,除非它成为问题或者您知道您处于性能危急情况并且特定断言将在主运行循环中运行数百或数千次。

Can't resist mentioning this article on asserts vs. NSAssert.

就个人而言,我开始删除我为调试目的而放入的那些,但是如果你使用asserts来检查数据完整性,参数,资源依赖性和其他相关的东西 - 可以说,你可以自己抛出异常,这可能更明智 - 然后我会留下他们。

注意:另一点是,删除断言完全是愚蠢的,因为你的应用程序会崩溃或处于不一致的状态,这两种情况都比以某种方式崩溃更糟糕从崩溃日志中识别(因此保留断言)。另一方面,用if语句替换断言可能是一件好事。

答案 1 :(得分:5)

我的建议:默认情况下,您应该将它们开启。我说:"努力工作,早早失败" - 并将错误修正保持在比功能更高的优先级。

然而,选择也很好 - 我不认为一种尺寸适合所有节目。出于这个原因,我使用了多种类型的断言。有些将在发布,有些则不会。我写了一个很多的错误检测,我也写了很多性能关键程序。我无法在发布版本的热门路径中留下大量的诊断和健全性检查。

不幸的是,它不能成为事后的想法(除非您准备优先考虑质量和测试开放时间)。如果你考虑一下,单一/传统方法也不能成为事后的想法。对于任一模型,最好在编写程序之前决定是否在发布中启用断言或哪些断言。


因此双断言模型的基本一般形式可能如下:

#include <assert.h>

/*
  MONDebugAssert assertion is active in debug and disabled in release.
  Recommendation: Always define NDEBUG (or not) in your build settings, 
  and nowhere else.
*/
#if defined(NDEBUG)
    #define MONDebugAssert(e) ((void)0)
#else
    #define MONDebugAssert(e) \
        (__builtin_expect(!(e), 0) ? __assert(#e, __FILE__, __LINE__) : (void)0)
#endif

/* MONAssert assertion is active at all times, including release builds. */
#define MONAssert(e) \
       (__builtin_expect(!(e), 0) ? __assert(#e, __FILE__, __LINE__) : (void)0)

其中__assert是平台断言处理程序。

然后在使用中:

MONDebugAssert(0); // << will fail in debug, and not in release.
MONAssert(0); // << will fail in any case

当然,很容易适应您的需求,或创建假定self在范围内的变体(如NSAssert)。

答案 2 :(得分:2)

在生产代码中总会有更好的事情要做,然后失败一个断言,但有时候这种权衡就会减少和干掉。

断言的好时机:继续操作会破坏用户数据(“已经有一个已知的好的保存文件,我已经检测到损坏的数据结构,如果我用我拥有的东西写好文件我会摧毁它”)。显然,“最佳”选项是首先不破坏数据。第二个最好的方法是在保存期间检测损坏的数据并保存到新文件中(它可能是可加载的,或者其中的内容足以通过英雄手段进行挽救)。

断言的另一个好时机:当你知道继续将崩溃时(将NULL传递给许多普通的C函数,即将除以零......)。断言将携带更多有用的信息。科西嘉更好的是没有进入那个州。第二好的是中止操作,而不是程序(“我无法打印”比“我丢弃未保存的数据,以及你无法打印的方式”更好)。

你几乎可以像这样打破局面。然而,错误恢复非常复杂,处理一些错误会使代码的大小增加一倍或者更糟,因为某些事情可能永远不会发生......然后你必须弄清楚如何测试它,并且......

......所以这是一个权衡。如果您避免错误恢复,您的程序中还有哪些更好?是否可以更好地弥补额外的崩溃?

答案 3 :(得分:1)

我的NSAssert失败表明出现了严重错误,继续进行将导致未定义的行为和数据损坏。我无法想象为什么人们会在发布版本中鹦鹉禁用它们。

如果您可以从中恢复,则应使用NSError代替。