断言的定义:
断言(assertion)是指在开发期间使用的、让程序在运行时进行自检的代码(通常是一个子程序或宏)。断言为真,则表明程序运行正常,而断言为假,则意味着它已经在代码中发现了意料之外的错误。断言对于大型的复杂程序或可靠性要求极高的程序来说尤其有用
断言使用的准则与建议:
- 用错误处理代码来处理预期会发生的状况,用断言来处理绝不应该发生的状况。
- 避免把需要执行的代码放到断言中
- 用断言来注解并验证前条件和后条件
- 对于高健壮性的代码,应该先使用断言再处理错误
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
- 使用NSAssert的时候,每个NSAssert只检验一个条件,因为同事检验多个条件时,如果断言失败,无法直观地判断是那个条件失败
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可以避免循环引用的发生。
频繁地调用会极大的影响程序的性能,增加额外开销。