我想知道在整个地方使用NSAssert是否是个好习惯?这样做有什么好处?在哪种情况下使用它是个好主意?
答案 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的断言机制通常是好的。例如: