155

我不得不问这个,因为:我唯一认识到的是,如果断言失败,应用程序就会崩溃。这就是使用 NSAssert 的原因吗?或者它还有什么好处?将 NSAssert 放在我在代码中所做的任何假设之上是否正确,例如一个永远不应接收 -1 作为参数但可能接收 -0.9 或 -1.1 的函数?

4

10 回答 10

300

断言是为了确保一个值是它应该是的。如果断言失败,则意味着出现问题,因此应用程序退出。使用 assert 的一个原因是,如果您有一些函数不会运行或会产生非常糟糕的副作用,如果传递给它的参数之一不完全是某个值(或值范围),您可以放置​​一个断言确保该值是您期望的值,如果不是,则确实有问题,因此应用程序退出。Assert 对于调试/单元测试非常有用,当你提供框架来阻止用户做“邪恶”的事情时也是如此。

于 2009-09-03T20:39:13.247 回答
20

我无法真正与 NSAssert 交谈,但我想它的工作方式类似于 C 的 assert()。

assert() 用于在代码中强制执行语义契约。你问这是什么意思?

好吧,就像你说的:如果你有一个永远不应该收到 -1 的函数,你可以让 assert() 强制执行:

无效 gimme_positive_ints(int i) {
  断言(我> 0);
}

现在您将在错误日志(或 STDERR)中看到类似的内容:

断言 i > 0 失败:文件 example.c,第 2 行

因此,它不仅可以防止潜在的错误输入,而且可以以有用的标准方式记录它们。

哦,至少在 C 中 assert() 是一个宏,因此您可以在发布代码中将 assert() 重新定义为无操作。我不知道 NSAssert 是否是这种情况(甚至是 assert() ),但编译出这些检查非常有用。

于 2009-09-03T20:49:08.727 回答
18

NSAssert给你的不仅仅是让应用程序崩溃。它告诉您断言发生的类、方法和行。所有断言也可以使用 NS_BLOCK_ASSERTIONS 轻松停用。从而使其更适合调试。另一方面,抛出一个NSException只会使应用程序崩溃。它也没有说明异常的位置,也不能这么简单地禁用它。请参阅下图中的差异。

应用程序崩溃是因为断言也会引发异常,正如NSAssert 文档所述:

调用时,断言处理程序会打印一条错误消息,其中包括方法和类名(或函数名)。然后它会引发一个 NSInternalInconsistencyException 异常。

NSA 断言:

断言后的日志

NS异常:

异常后的日志

于 2014-09-10T13:07:54.323 回答
17

除了上面每个人所说的之外,NSAssert()(与 C 不同assert())的默认行为是抛出异常,您可以捕获并处理它。例如,Xcode 就是这样做的。

于 2009-09-03T21:01:54.237 回答
9

只是为了澄清,正如有人提到但没有完全解释的那样,拥有和使用断言而不是仅仅创建自定义代码(例如,执行 if 并为坏数据引发异常)的原因是,应该为生产应用程序禁用断言。

在开发和调试时,启用断言以捕获错误。当断言被评估为假时,程序将停止。但是,在为生产进行编译时,编译器会省略断言代码,实际上让您的程序运行得更快。到那时,希望你已经修复了所有的错误。如果您的程序在生产过程中仍然存在错误(当断言被禁用并且程序“跳过”断言时),您的程序可能最终会在其他时候崩溃。

来自 NSAssert 的帮助:“如果定义了预处理器宏 NS_BLOCK_ASSERTIONS,则断言将被禁用。” 因此,只需将宏放在您的分发目标中[仅]。

于 2010-09-22T16:02:11.330 回答
6

NSAssert(及其 stdlib 等效项assert)用于在开发过程中检测编程错误。在生产(已发布)应用程序中,您永远不应该有一个失败的断言。因此,您可能会断言您永远不会将负数传递给需要正参数的方法。如果断言在测试期间失败了,那么你就有了一个错误。但是,如果传递的值是由用户输入的,您需要对输入进行适当的验证,而不是依赖于生产中的断言(您可以为发布版本设置一个 #define 来禁用NSAssert*.

于 2009-09-03T20:49:02.240 回答
3

值得指出的是,除了运行时检查之外,断言编程是您通过合同设计代码时使用的重要工具。

关于断言和合同设计主题的更多信息可以在下面找到:

断言(软件开发)

合同设计

断言编程

按合同设计,通过示例 [平装本]

于 2011-04-06T16:30:13.410 回答
3

断言通常用于强制执行特定方法或逻辑片段的预期用途。假设您正在编写一个计算两个大于零整数之和的方法。为了确保该方法始终按预期使用,您可能会放置一个断言来测试该条件。

简短的回答:他们强制您的代码仅按预期使用。

于 2009-09-03T20:48:21.867 回答
2

为了完全回答他的问题,任何类型的断言都是为了帮助调试。更有价值的是从源头捕获错误,然后在它们导致崩溃时在调试器中捕获它们。

例如,您可以将一个值传递给一个期望某个范围内的值的函数。该函数可以存储该值以供以后使用,并在以后使用时应用程序崩溃。在这种情况下看到的调用堆栈不会显示错误值的来源。最好在出现错误值时捕获错误值,以找出谁传递了错误值以及原因。

于 2009-11-03T22:06:54.593 回答
-3

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”
于 2014-11-20T10:32:35.030 回答