是否应该在生产iOS应用程序中声明?

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

我testing我的应用程序,但是,鉴于我不是Knuth( 写1美元的支票),我不能像一些医疗和空间系统软件公司那样雇用一大批全职QA人员,假设所有应用程序总是会有很多在testing或质量保证期间从未见过的错误。 假设在其他方面看起来在理智上是不诚实的。 因此,在testing一个应用程序(并明显消除导致之前看到的ASSERT失败的所有错误)并准备将应用程序发送给Apple之后,应该如何处理Release / Distribution构build中的所有ASSERT检查? 离开还是不离开?

这里有一个让他们理解的基本原理:如果某个应用程序对某些用户来说太不可思议了,那么这个应用程序可能会被这些用户评为一星级,而没有人会告诉开发人员足够的细节。 但是,如果应用程序崩溃,从一个ASSERT失败,应用程序可能仍然获得1星级,但开发人员可能会得到一些崩溃转储间接通过iTunes和iTunes连接,如果有足够的用户select,找出哪里出了问题。 如果应用程序因为全新的ASSERT崩溃而被苹果拒绝,那么将会阻止恶意应用程序版本进入客户的设备。

把它们留在原来的位置上,也是因为在某些情况下,它们作为注释(特别是Objective-C中的types)。 除非成为问题,否则不要担心性能问题,或者您知道自己处于性能危机的情况,并且主要运行循环中的特定断言将运行数百或数千次。

不能拒绝提到这篇文章关于断言与NSAssert。

就个人而言,我开始删除为debugging目的而放置的那些,但如果使用断言来检查数据完整性,参数,资源依赖性和其他相关的事情 – 可以说,您可以自己抛出exception,这可能是更聪明 – 那么我会让他们进来。

注意:还有一点是,删除断言是非常愚蠢的,因为你的应用程序可能会崩溃或处于不一致的状态,这两种情况都比以崩溃日志的方式崩溃更糟糕(所以请保留断言在)。 换句话说, if语句,另一方面,可能是一件好事。

我的build议:你应该保持默认状态。 我会说:“努力失败,失败早” – 并且保留比function更高的优先级。

不过,select也不错 – 我不认为所有的项目都适合。 出于这个原因,我使用了多种types的断言。 有些会被释放,有些则不会。 我写了很多错误检测,并且还编写了很多性能关键的程序。 我不能在版本构build的热门path上留下大量的诊断和完整性检查。

不幸的是,这不可能是事后的想法(除非你准备把质量和testing放在一个开放的时间上)。 如果你仔细想一想,单一的/传统的方法也不是事后的想法。 无论使用哪种模式, 编写程序之前 ,最好决定是否在版本中启用断言或哪些断言。


因此,双重声明模型的基本一般forms可能如下所示:

 #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 

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

在生产代码中往往会有更好的做法,然后失败,但是有时这种折衷不会被削减和干涸。

一个好的时机来断言:当继续的时候会破坏用户数据(“已经有一个已知的好的保存文件,并且我已经检测到损坏的数据结构,如果我用我所拥有的东西写好的文件,我会销毁它” )。 很明显,“最好”的select是首先不损害数据。 其次,在保存过程中检测损坏的数据并保存到一个新的文件中(可能是可加载的,或者可能是通过英雄手段挽救的)。

另一个好的时机来断言:当你知道继续会崩溃(将NULL传递给许多普通的C函数,即将被零除…)。 断言将携带更多有用的信息。 更糟的是没有进入这个状态。 第二好的是中止操作,而不是程序(“我不能打印”更好,“我扔掉了未保存的数据,顺便说一句,你不能打印”)。

你几乎总能把事情分解成这样。 然而,错误恢复是相当复杂的,交付一些错误会加倍或更糟的代码的大小,可能永远不会发生的事情…然后你必须弄清楚如何testing,并…

…所以这是一个折衷。 如果你在错误恢复上吝啬,你的程序中还有什么更好的? 弥补额外的崩溃会更好吗?

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

如果你可以从中恢复,你应该使用NSError来代替。