NSAssert()是一個(gè)宏宪躯,用于開(kāi)發(fā)階段調(diào)試程序中的Bug,通過(guò)為NSAssert()傳遞條件表達(dá)式來(lái)斷定是否屬于Bug位迂,滿足條件返回真值访雪,程序繼續(xù)運(yùn)行,如果返回假值掂林,則拋出異常臣缀,并且可以自定義異常描述。
NSAssert()是這樣定義的:
#define NSAssert(condition, desc)
condition是條件表達(dá)式泻帮,值為YES或NO精置;desc為異常描述,通常為NSString锣杂。當(dāng)conditon為YES時(shí)程序繼續(xù)運(yùn)行脂倦,為NO時(shí),則拋出帶有desc描述的異常信息蹲堂。NSAssert()可以出現(xiàn)在程序的任何一個(gè)位置狼讨。
NSAssert和assert 區(qū)別
NSAssert和assert都是斷言,主要的差別是assert在斷言失敗的時(shí)候只是簡(jiǎn)單的終止程序,而NSAssert會(huì)報(bào)告出錯(cuò)誤信息并且打印出來(lái).所以只使用NSAssert就好,可以不去使用assert。
NSAssert/NSCAssert
iOS中用的最多的是兩對(duì)斷言, NSAssert/NSCAssert 和 NSParameterAssert/NSCparameterAssert. 要知道他們的區(qū)別,我們先來(lái)看看他們定義.
#if !defined(NS_BLOCK_ASSERTIONS)
#if !defined(_NSAssertBody)
#define NSAssert(condition, desc, ...) \\\\
do { \\\\
__PRAGMA_PUSH_NO_EXTRA_ARG_WARNINGS \\\\
if (!(condition)) { \\\\
[[NSAssertionHandler currentHandler] handleFailureInMethod:_cmd \\\\
object:self file:[NSString stringWithUTF8String:__FILE__] \\\\
lineNumber:__LINE__ description:(desc), ##__VA_ARGS__]; \\\\
} \\\\
__PRAGMA_POP_NO_EXTRA_ARG_WARNINGS \\\\
} while(0)
#endif
#if !defined(_NSCAssertBody)
#define NSCAssert(condition, desc, ...) \\\\
do { \\\\
__PRAGMA_PUSH_NO_EXTRA_ARG_WARNINGS \\\\
if (!(condition)) { \\\\
[[NSAssertionHandler currentHandler] handleFailureInFunction:[NSString stringWithUTF8String:__PRETTY_FUNCTION__] \\\\
file:[NSString stringWithUTF8String:__FILE__] \\\\
lineNumber:__LINE__ description:(desc), ##__VA_ARGS__]; \\\\
} \\\\
__PRAGMA_POP_NO_EXTRA_ARG_WARNINGS \\\\
} while(0)
#endif
從定義可以看出來(lái)柒竞,前者是適合于ObjectC的方法政供,_cmd 和 self 與運(yùn)行時(shí)有關(guān). 后者是適用于C的函數(shù)。
NSParameterAssert/NSCparameterAssert 兩者的區(qū)別也是前者適用于Objective-C的方法,后者適用于C的函數(shù)朽基。
實(shí)際開(kāi)發(fā)中就用前者就可以了布隔。
NSAssert/NSCAssert 和 NSParameterAssert/NSCparameterAssert 的區(qū)別是前者是針對(duì)條件斷言, 后者只是針對(duì)參數(shù)是否存在的斷言, 調(diào)試時(shí)候可以結(jié)合使用,先判斷參數(shù),再進(jìn)一步斷言稼虎,確認(rèn)原因.
NSAssert的用法
int a = 1;
NSCAssert(a == 2, @"a must equal to 2"); //第一個(gè)參數(shù)是條件,如果第一個(gè)參數(shù)不滿足條件,就會(huì)記錄并打印后面的字符串
運(yùn)行則會(huì)崩潰并在控制臺(tái)輸出信息如下:
*** Assertion failure in -[ViewController viewDidLoad](), /Users/yinwentao/Desktop/MYAssert/MYAssert/ViewController.m:32
*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'a must equal to 2'
NSParameterAssert的用法
- (void)assertWithPara:(NSString *)str
{
NSParameterAssert(str); //只需要一個(gè)參數(shù),如果參數(shù)存在程序繼續(xù)運(yùn)行,如果參數(shù)為空,則程序停止打印日志
//further code ...
}
如果 調(diào)用方法 assertWithPara: 傳入?yún)?shù)為空則有如下日志
*** Assertion failure in -[ViewController assertWithPara:], /Users/yinwentao/Desktop/MYAssert/MYAssert/ViewController.m:45
*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Invalid parameter not satisfying: str'
日志中的數(shù)字是告訴你 第多少行代碼出錯(cuò)了衅檀。
Xcode 已經(jīng)默認(rèn)將release環(huán)境下的斷言取消了, 免除了忘記關(guān)閉斷言造成的程序不穩(wěn)定. 所以不用擔(dān)心 在開(kāi)發(fā)時(shí)候大膽使用。
自定義NSAssertionHandler
NSAssertionHandler實(shí)例是自動(dòng)創(chuàng)建的霎俩,用于處理錯(cuò)誤斷言哀军。如果 NSAssert和NSCAssert條件評(píng)估為錯(cuò)誤,會(huì)向 NSAssertionHandler實(shí)例發(fā)送一個(gè)表示錯(cuò)誤的字符串打却。每個(gè)線程都有它自己的NSAssertionHandler實(shí)例杉适。
我們可以自定義處理方法,從而使用斷言的時(shí)候柳击,控制臺(tái)輸出錯(cuò)誤猿推,但是程序不會(huì)直接崩潰。
#import "MyAssertHandler.h"
@implementation MyAssertHandler
//處理Objective-C的斷言
- (void)handleFailureInMethod:(SEL)selector object:(id)object file:(NSString *)fileName lineNumber:(NSInteger)line description:(NSString *)format,...
{
NSLog(@"NSAssert Failure: Method %@ for object %@ in %@#%li", NSStringFromSelector(selector), object, fileName, (long)line);
}
//處理C的斷言
- (void)handleFailureInFunction:(NSString *)functionName file:(NSString *)fileName lineNumber:(NSInteger)line description:(NSString *)format,...
{
NSLog(@"NSCAssert Failure: Function (%@) in %@#%li", functionName, fileName, (long)line);
}
@end
給線程添加處理類
NSAssertionHandler *myHandler = [[MyAssertHandler alloc] init];
//給當(dāng)前的線程
[[[NSThread currentThread] threadDictionary] setValue:myHandler
forKey:NSAssertionHandlerKey];
自定義NSAssertionHandler后,程序能夠獲得斷言失敗后的信息,但是程序可以繼續(xù)運(yùn)行,不會(huì)強(qiáng)制退出程序.