我不得不问这个,因为:我唯一认识到的是,如果断言失败,应用程序就会崩溃。这就是使用 NSAssert 的原因吗?或者它还有什么好处?将 NSAssert 放在我在代码中所做的任何假设之上是否正确,例如一个永远不应接收 -1 作为参数但可能接收 -0.9 或 -1.1 的函数?
10 回答
断言是为了确保一个值是它应该是的。如果断言失败,则意味着出现问题,因此应用程序退出。使用 assert 的一个原因是,如果您有一些函数不会运行或会产生非常糟糕的副作用,如果传递给它的参数之一不完全是某个值(或值范围),您可以放置一个断言确保该值是您期望的值,如果不是,则确实有问题,因此应用程序退出。Assert 对于调试/单元测试非常有用,当你提供框架来阻止用户做“邪恶”的事情时也是如此。
我无法真正与 NSAssert 交谈,但我想它的工作方式类似于 C 的 assert()。
assert() 用于在代码中强制执行语义契约。你问这是什么意思?
好吧,就像你说的:如果你有一个永远不应该收到 -1 的函数,你可以让 assert() 强制执行:
无效 gimme_positive_ints(int i) { 断言(我> 0); }
现在您将在错误日志(或 STDERR)中看到类似的内容:
断言 i > 0 失败:文件 example.c,第 2 行
因此,它不仅可以防止潜在的错误输入,而且可以以有用的标准方式记录它们。
哦,至少在 C 中 assert() 是一个宏,因此您可以在发布代码中将 assert() 重新定义为无操作。我不知道 NSAssert 是否是这种情况(甚至是 assert() ),但编译出这些检查非常有用。
NSAssert
给你的不仅仅是让应用程序崩溃。它告诉您断言发生的类、方法和行。所有断言也可以使用 NS_BLOCK_ASSERTIONS 轻松停用。从而使其更适合调试。另一方面,抛出一个NSException
只会使应用程序崩溃。它也没有说明异常的位置,也不能这么简单地禁用它。请参阅下图中的差异。
应用程序崩溃是因为断言也会引发异常,正如NSAssert 文档所述:
调用时,断言处理程序会打印一条错误消息,其中包括方法和类名(或函数名)。然后它会引发一个 NSInternalInconsistencyException 异常。
NSA 断言:
NS异常:
除了上面每个人所说的之外,NSAssert()
(与 C 不同assert()
)的默认行为是抛出异常,您可以捕获并处理它。例如,Xcode 就是这样做的。
只是为了澄清,正如有人提到但没有完全解释的那样,拥有和使用断言而不是仅仅创建自定义代码(例如,执行 if 并为坏数据引发异常)的原因是,应该为生产应用程序禁用断言。
在开发和调试时,启用断言以捕获错误。当断言被评估为假时,程序将停止。但是,在为生产进行编译时,编译器会省略断言代码,实际上让您的程序运行得更快。到那时,希望你已经修复了所有的错误。如果您的程序在生产过程中仍然存在错误(当断言被禁用并且程序“跳过”断言时),您的程序可能最终会在其他时候崩溃。
来自 NSAssert 的帮助:“如果定义了预处理器宏 NS_BLOCK_ASSERTIONS,则断言将被禁用。” 因此,只需将宏放在您的分发目标中[仅]。
NSAssert
(及其 stdlib 等效项assert
)用于在开发过程中检测编程错误。在生产(已发布)应用程序中,您永远不应该有一个失败的断言。因此,您可能会断言您永远不会将负数传递给需要正参数的方法。如果断言在测试期间失败了,那么你就有了一个错误。但是,如果传递的值是由用户输入的,您需要对输入进行适当的验证,而不是依赖于生产中的断言(您可以为发布版本设置一个 #define 来禁用NSAssert*
.
值得指出的是,除了运行时检查之外,断言编程是您通过合同设计代码时使用的重要工具。
关于断言和合同设计主题的更多信息可以在下面找到:
断言通常用于强制执行特定方法或逻辑片段的预期用途。假设您正在编写一个计算两个大于零整数之和的方法。为了确保该方法始终按预期使用,您可能会放置一个断言来测试该条件。
简短的回答:他们强制您的代码仅按预期使用。
为了完全回答他的问题,任何类型的断言都是为了帮助调试。更有价值的是从源头捕获错误,然后在它们导致崩溃时在调试器中捕获它们。
例如,您可以将一个值传递给一个期望某个范围内的值的函数。该函数可以存储该值以供以后使用,并在以后使用时应用程序崩溃。在这种情况下看到的调用堆栈不会显示错误值的来源。最好在出现错误值时捕获错误值,以找出谁传递了错误值以及原因。
NSAssert
与条件匹配时使应用程序崩溃。如果与条件不匹配,则将执行下一条语句。寻找下面的EX:
我只是创建一个应用程序来测试任务NSAssert
是什么:
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
[self testingFunction:2];
}
-(void)testingFunction: (int)anNum{
// if anNum < 2 -> the app will crash
// and the NSLog statement will not execute
// that mean you cannot see the string: "This statement will execute when anNum < 2"
// into the log console window of Xcode
NSAssert(anNum >= 2, @"number you enter less than 2");
// If anNum >= 2 -> the app will not crash and the below
// statement will execute
NSLog(@"This statement will execute when anNum < 2");
}
进入我的代码应用程序不会崩溃。测试用例是:
anNum
>= 2 -> 应用程序不会崩溃,您可以在输出日志控制台窗口中看到日志字符串:“This statement will execute when anNum < 2”anNum
< 2 -> 应用会崩溃,看不到日志字符串:“This statement will execute when anNum < 2”