实际上,NSAssert有什么意义?


155

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

Answers:


300

断言是要确保值是应该的值。如果断言失败,则意味着出现了问题,因此应用程序退出。使用assert的原因之一是,如果传递给它的参数之一不是某个值(或一系列值),则您可以使用某些函数将不起作用或会产生非常严重的副作用,可以使用assert来进行确保该值就是您期望的值,如果不是,则说明确实存在错误,因此该应用程序退出。断言对于调试/单元测试以及提供阻止用户执行“邪恶”操作的框架非常有用。


9
您应该取出NSAssert进行发布。有一个编译时标志可以做到这一点。
巴里·沃克

127
>您应该取出NSAssert进行发布。这值得商.。我总是在启用断言的情况下发布应用程序,这是许多软件的标准做法,例如Apple就是这样做的。一旦程序检测到异常状态,您应该崩溃。您可以获取错误发生位置的堆栈跟踪记录,而如果禁用断言,则可能最终损坏内存和/或用户数据,并且很难调试该问题。
Mike Weller 2010年

18
请注意,在发布配置中,默认情况下,XCode 4具有NS_BLOCK_ASSERTIONS定义。我猜如果您不更改,您发布的代码将不包含NSAssert:s。
乔尼

16
如果我理解正确,将它们留在发行版上有什么意义?为什么不使用if语句和if(如果发生了某些可怕的事情)替换NSAssert,然后通知用户(或执行控制下事情),而不仅仅是退出/崩溃并让用户想知道发生了什么...或者我错过了什么吗?
Gik 2012年

11
在正常情况下根本不应该发生的所有例外情况下,浪费开发人员的时间。这涉及到考虑适当的方式来通知用户每个用户和/或使应用足够健壮以在用户出现之后以预期方式继续进行。更为实用的方法是使应用程序崩溃,并修复崩溃报告中发现的错误并发布新版本。话虽如此,重要的是要确保在任何这种情况下都不会丢失数据。尽管如此,必须确保这一点,但是工作量要小得多。
2013年

20

我真的不能和NSAssert交谈,但是我认为它的工作方式与C的assert()类似。

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

好吧,就像您说的那样:如果您有一个永远不应该收到-1的函数,则可以使assert()强制执行以下操作:

void gimme_positive_ints(int i){
  断言(i> 0);
}

现在,您将在错误日志(或STDERR)中看到以下内容:

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

因此,它不仅可以安全防范潜在的不良输入,而且还可以以一种有用的标准方式记录它们。

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


2
是的,NSAssert也是一个宏。
Martin Wickman

18

NSAssert给您带来的不仅仅是崩溃应用程序。它告诉您断言的类,方法和行。还可以使用NS_BLOCK_ASSERTIONS轻松停用所有断言。从而使其更适合调试。另一方面,NSException仅抛出则会使应用程序崩溃。它也不能告知异常的位置,也不能如此简单地将其禁用。请参见以下图片中的区别。

应用程序崩溃,因为声明也引发了异常,如NSAssert文档所述:

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

NSAssert:

断言后记录

NSException:

发生异常后记录


An NSException提供了很多机会来定制通过reasonuserInfo参数返回的输出。没有理由不添加类名,选择器,行信息以及您想要添加以帮助调试的其他任何内容。恕我直言,您可以NSAssert在开发过程中将用作调试目的,但禁用它们;NSException如果要保留运输代码中的断言,则抛出。
markeissler

17

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


还有更多关于如何捕获和处理异常的信息吗?
2013年

1
实际上,可可中的异常并非“可捕获且可处理的”。如果控件在调用树中的所有位置都通过apple函数传递,则行为是不确定的。异常纯粹是用于错误报告(又名,crittercism等),而不是像Java那样一般使用。
2014年

9

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

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

来自NSAssert的帮助:“如果定义了预处理程序宏NS_BLOCK_ASSERTIONS,则将禁用断言。” 因此,只需将宏放入您的分发目标中(仅)。


6

NSAssert(及其等效的stdlib assert)用于在开发过程中检测编程错误。在生产(已发布)的应用程序中,永远不要有失败的断言。因此,您可能会断言,永远不要将负数传递给需要正数的方法。如果断言在测试期间失败,则说明您有错误。但是,如果传递的值是由用户输入的,则需要对输入进行适当的验证,而不是依赖生产中的断言(您可以为#build设置禁用的release构建NSAssert*


2
+1是因为您的回答对我来说最有意义!如果将NSAssert用于开发而不是发布后使用,则更有意义。用户输入不允许的值后应出现UI错误,而不是NSAssert使应用程序崩溃。雾已经清除了!
pnizzle

3

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

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



2

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

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


-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->应用程序将不会崩溃,并且您可以在outPut日志控制台窗口中看到日志字符串:“当anNum <2时将执行此语句”
  • anNum <2->应用程序将崩溃,并且您无法看到日志字符串:“此语句将在anNum <2时执行”

1
相反,您已经掌握了它。“ NSAssert与条件匹配时会使应用程序崩溃。如果与条件不匹配,则将执行下一条语句”。如果不符合条件,NSAssert将使应用程序崩溃,如果不符合条件,则NSAssert将正常执行。
Joe Tam

不符合条件的应用会崩溃并记录消息,否则它将进一步执行。
Pravin S.
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.