NSAssert()是一個宏,用于開發階段調試程序中的Bug,通過為NSAssert()傳遞條件表達式來斷定是否屬于Bug,滿足條件返回真值,程序繼續運行,如果返回假值,則拋出異常,并且可以自定義異常描述。
NSAssert()是這樣定義的:
#define NSAssert(condition, desc)
condition是條件表達式,值為YES或NO;desc為異常描述,通常為NSString。當conditon為YES時程序繼續運行,為NO時,則拋出帶有desc描述的異常信息。NSAssert()可以出現在程序的任何一個位置。
NSAssert和assert 區別
NSAssert和assert都是斷言,主要的差別是assert在斷言失敗的時候只是簡單的終止程序,而NSAssert會報告出錯誤信息并且打印出來.所以只使用NSAssert就好,可以不去使用assert。
NSAssert/NSCAssert
iOS中用的最多的是兩對斷言, NSAssert/NSCAssert 和 NSParameterAssert/NSCparameterAssert. 要知道他們的區別,我們先來看看他們定義.
#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
從定義可以看出來,前者是適合于ObjectC的方法,_cmd 和 self 與運行時有關. 后者是適用于C的函數。
NSParameterAssert/NSCparameterAssert 兩者的區別也是前者適用于Objective-C的方法,后者適用于C的函數。
實際開發中就用前者就可以了。
NSAssert/NSCAssert 和 NSParameterAssert/NSCparameterAssert 的區別是前者是針對條件斷言, 后者只是針對參數是否存在的斷言, 調試時候可以結合使用,先判斷參數,再進一步斷言,確認原因.
NSAssert的用法
int a = 1;
NSCAssert(a == 2, @"a must equal to 2"); //第一個參數是條件,如果第一個參數不滿足條件,就會記錄并打印后面的字符串
運行則會崩潰并在控制臺輸出信息如下:
*** 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); //只需要一個參數,如果參數存在程序繼續運行,如果參數為空,則程序停止打印日志
//further code ...
}
如果 調用方法 assertWithPara: 傳入參數為空則有如下日志
*** 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'
日志中的數字是告訴你 第多少行代碼出錯了。
Xcode 已經默認將release環境下的斷言取消了, 免除了忘記關閉斷言造成的程序不穩定. 所以不用擔心 在開發時候大膽使用。
自定義NSAssertionHandler
NSAssertionHandler實例是自動創建的,用于處理錯誤斷言。如果 NSAssert和NSCAssert條件評估為錯誤,會向 NSAssertionHandler實例發送一個表示錯誤的字符串。每個線程都有它自己的NSAssertionHandler實例。我們可以自定義處理方法,從而使用斷言的時候,控制臺輸出錯誤,但是程序不會直接崩潰。
#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];//給當前的線程[[[NSThread currentThread] threadDictionary] setValue:myHandler forKey:NSAssertionHandlerKey];
自定義NSAssertionHandler后,程序能夠獲得斷言失敗后的信息,但是程序可以繼續運行,不會強制退出程序.