断言

断言的定义:

断言(assertion)是指在开发期间使用的、让程序在运行时进行自检的代码(通常是一个子程序或宏)。断言为真,则表明程序运行正常,而断言为假,则意味着它已经在代码中发现了意料之外的错误。断言对于大型的复杂程序或可靠性要求极高的程序来说尤其有用

断言使用的准则与建议:

  1. 用错误处理代码来处理预期会发生的状况,用断言来处理绝不应该发生的状况。
  2. 避免把需要执行的代码放到断言中
  3. 用断言来注解并验证前条件和后条件
  4. 对于高健壮性的代码,应该先使用断言再处理错误
《代码大全2》-防御式编程

NSAssert()

NSAssert()是一个宏,用于开发阶段调试程序中的Bug,通过为NSAssert()传递条件表达式来断定是否属于Bug,满足条件返回真值,程序继续运行,如果返回假值,则抛出异常,并且可以自定义异常描述。

#define NSAssert(condition, desc)

  • condition是条件表达式,值为YES或NO;
  • desc为异常描述,通常为NSString。
  • 当conditon为YES时程序继续运行,为NO时,则抛出带有desc描述的异常信息。NSAssert()可以出现在程序的任何一个位置。

NSAssert和assert 区别

NSAssert和assert都是断言,主要的差别是assert在断言失败的时候只是简单的终止程序,而NSAssert会报告出错误信息并且打印出来.所以只使用NSAssert就好,可以不去使用assert。

断言何时运行?

通常在debug情况下(真机中会自动忽略),所有NSAssert都会被执行。在release下系统会自动将断言设置为禁用。如果release下断言仍可执行的话,则需要我们手动设置为,设置方式如下:Preprocessor Macros 的Release值为 NS_BLOCK_ASSERTIONS。

小延伸:如何切换Debug和Release呢?

自答吧:
1、点击工程名,点这里。选择Edit Scheme
2、选择Run,在Info 中将Build Configuration 修改为release

NOTE

  1. 使用NSAssert的时候,每个NSAssert只检验一个条件,因为同事检验多个条件时,如果断言失败,无法直观地判断是那个条件失败
  2. Block中使用NSAssert要特别注意循环引用。
    有没有搞错,用断言也会出现循环引用,不信,那我们看看宏定义展开后是啥样的?:

       #define NSAssert(condition, desc, ...)	\
       do {				\
    __PRAGMA_PUSH_NO_EXTRA_ARG_WARNINGS \
    if (!(condition)) {		\
               NSString *__assert_file__ = [NSString stringWithUTF8String:__FILE__]; \
               __assert_file__ = __assert_file__ ? __assert_file__ : @"<Unknown File>"; \
        [[NSAssertionHandler currentHandler] handleFailureInMethod:_cmd \
    	object:self file:__assert_file__ \
        	lineNumber:__LINE__ description:(desc), ##__VA_ARGS__]; \
    }				\
           __PRAGMA_POP_NO_EXTRA_ARG_WARNINGS \
       } while(0)
       

    看到没,宏定义展开后会出现对self的持有,容易导致循环引用!!!。有没有解决方法,必须呀,使用 NSCAssert!,你确信吗?不信,展开看看:

       #define NSCAssert(condition, desc, ...) \
       do {				\
    __PRAGMA_PUSH_NO_EXTRA_ARG_WARNINGS \
    if (!(condition)) {		\
               NSString *__assert_fn__ = [NSString stringWithUTF8String:__PRETTY_FUNCTION__]; \
               __assert_fn__ = __assert_fn__ ? __assert_fn__ : @"<Unknown Function>"; \
               NSString *__assert_file__ = [NSString stringWithUTF8String:__FILE__]; \
               __assert_file__ = __assert_file__ ? __assert_file__ : @"<Unknown File>"; \
        [[NSAssertionHandler currentHandler] handleFailureInFunction:__assert_fn__ \
    	file:__assert_file__ \
        	lineNumber:__LINE__ description:(desc), ##__VA_ARGS__]; \
    }				\
           __PRAGMA_POP_NO_EXTRA_ARG_WARNINGS \
       } while(0)
       

    宏定义中并没有出现self,所以在block中使用NSCAssert可以避免循环引用的发生。

  3. 频繁地调用会极大的影响程序的性能,增加额外开销。


   转载规则


《断言》 志鹏 采用 知识共享署名 4.0 国际许可协议 进行许可。
 上一篇
NSPredicate NSPredicate
NSPredicate是什么?NSPredicate是一个Foundation类,它指定数据被获取或者过滤的方式。它的查询语言就像SQL的WHERE和正则表达式的交叉一样,提供了具有表现力的,自然语言界面来定义一个集合被搜寻的逻辑条件 集合
2017-07-12
下一篇 
监听NSMutableArray的变化 监听NSMutableArray的变化
平时工作中我们接触最多的容器,可能就数字典与数组了。有时我们在使用这些容器时有这样一个困惑,容器中的数据改变了,我们却无法立即知道。近日小编因为这个感到有些小苦恼,思来想去发现还是有途径可以做到监听容器的变化。接下来我将会用文字将我的想法叙
2017-07-10
  目录