什么是断言或NSAssert在实践中有益?

时间:2009-09-03 16:23:28

标签: iphone cocoa-touch uikit

我想知道在整个地方使用NSAssert是否是个好习惯?这样做有什么好处?在哪种情况下使用它是个好主意?

4 个答案:

答案 0 :(得分:27)

广泛使用NSAssert()不会将ObjC变成艾菲尔,但只要你记住它是如何实际实现的以及它在做什么,它仍然是一个相当不错的做法。有关NSAssert()

的注意事项

默认情况下,Xcode在发布模式下不会关闭NSAssert()。您必须记住在xcconfig中将NS_BLOCK_ASSERTIONS添加到GCC_PREPROCESSOR_DEFINITIONS。 (你是{{​​3}},对吗?)一个常见的问题是在nil会安静地工作的情况下断言非零;这可能意味着可以优雅恢复的事情发生现场崩溃。这与NDEBUG使用的assert()宏无关,如果您的代码包含两种类型的断言,则必须记住定义它们。

如果您在发布模式下编译NSAssert(),那么当客户向您发送日志时,您无法指出问题发生的位置。我亲自将NSAssert()包装在我自己的宏中,即使在发布模式下也始终记录。

NSAssert()经常强制重复逻辑。考虑测试C ++指针为NULL的情况。您使用NSAssert(),但仍然需要使用简单的if()测试,以避免在现场崩溃。这种重复的代码可能成为bug的来源,我看到由于断言不再有效而导致代码失败。 (幸运的是,这通常是在调试模式下!)我已经讨论了很多如何创建一个结合断言和if()的宏,但很难做到没有脆弱或难以理解代码。

由于上一个问题,我通常将“NSAssert(NO, ...)”放在else{}子句中,而不是在方法的顶部执行断言。这并不理想,因为它使合同远离方法签名(从而减少了其文件利益),但这是我在实践中发现的最有效的方法。

答案 1 :(得分:9)

主要警告是副作用。如果你写:

NSAssert([self.navigationController popViewControllerAnimated:YES]!=nil,@"Something fails");

popViewControllerAnimated:将在调试版本中执行,但不会在剥离NSAssert()的发行版中执行。这意味着您的发行版本的行为与调试版本不同。

如果你足够小心,这个问题就会消失:

UIViewController* vc = [self.navigationController popViewControllerAnimated:YES]; 
NSAssert(vc!=nil,@"Something fails");

答案 2 :(得分:7)

调试。每当你编写代码时,你几乎总是在做假设。关于环境状态,参数值,局部变量和字段等的假设。通常,这些假设都是错误的(一位老同事给了我一个好的格言,“假设是所有fsckups的母亲”)

存在断言以验证您的假设,在您制作它们时。你有一个方法

void foo(int x)
{
   …
}

您知道并且记录的仅适用于x> 5?断言!

断言与单元测试和正式方法一起作为良好编码实践的一部分。虽然有些人可能认为全面的单元测试确保断言是多余的,但事实并非如此。例如,您可能会假设一种方法,例如,员工总是超过16岁且不到100岁 - 但目前代码并不需要这样做。通过这些参数的单元测试将会成功,但是稍后当您需要使用您的假设时,您将拥有通过测试的所有代码,但是错误。

答案 3 :(得分:6)

我强烈推荐这篇文章

http://www.mikeash.com/pyblog/friday-qa-2013-05-03-proper-use-of-asserts.html

正如文章所述,使用不是NSAssert的断言机制通常是好的。例如:

https://github.com/hfossli/AGAssert