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

16 iphone cocoa-touch uikit

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

Rob*_*ier 27

广泛使用NSAssert()不会将ObjC变成Eiffel,但只要你记住它实际上是如何实现的以及它正在做什么,它仍然是一个相当不错的实践.要记住的事情NSAssert():

NSAssert()默认情况下,Xcode 在"释放"模式下不会关闭.你必须记住添加NS_BLOCK_ASSERTIONSGCC_PREPROCESSOR_DEFINITIONS你xcconfig.(你正在使用xcconfigs,对吗?)一个常见的问题是在nil会安静地工作的情况下断言非nil; 这可能意味着可以优雅恢复的事情发生现场崩溃.这与使用的NDEBUG宏无关assert(),并且您必须记住定义两者是否包含两种类型的断言.

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

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

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


Fre*_*man 9

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

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

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

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

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


Ada*_*ght 7

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

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

void foo(int x)
{
   …
}
Run Code Online (Sandbox Code Playgroud)

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

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


hfo*_*sli 6

我强烈推荐这篇文章

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

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

https://github.com/hfossli/AGAssert