NSAssert和assert是斷言,主要的差別是assert在斷言失敗的時候只是簡單的終止程序,而NSAssert會報告出錯誤信息並且打印出來.所以盡管的使用NSAssert,可以不去使用assert.
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
NSAssert/NSCAssert 兩者的差別通過定義可以看出來, 前者是適合於Objective-C的方法,_cmd 和 self 與運行時有關. 后者是適用於C的函數.
NSParameterAssert/NSCparameterAssert兩者的區別也是前者適用於Objective-C的方法,后者適用於C的函數.
NSAssert/NSCAssert 和 NSParameterAssert/NSCparameterAssert 的區別是前者是所有斷言, 后者只是針對參數是否存在的斷言, 所以可以先進行參數的斷言,確認參數是正確的,再進行所有的斷言,確認其他原因.
NSAssert的用法
- int a = 4;
- NSAssert(a == 5, @"a must equal to 5"); //第一個參數是條件,如果第一個參數不滿足條件,就會記錄和打印第二個參數
- //回記錄並打印斷言日志
- *** Assertion failure in -[AppDelegate application:didFinishLaunchingWithOptions:], /Users/admin/Desktop/storyboard/storyboard/AppDelegate.m:36
- *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'a must equal to 5
NSParameterAssert的用法
- - (void)assertWithPara:(NSString *)str
- {
- NSParameterAssert(str); //只需要一個參數,如果參數存在程序繼續運行,如果參數為空,則程序停止打印日志
- //further code ...
- }
- // 如果str 為空則有如下類似的日志
- *** Assertion failure in -[AppDelegate assertWithPara:], /Users/admin/Desktop/storyboard/storyboard/AppDelegate.m:45<pre name="code" class="objc">*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Invalid parameter not satisfying: str'
Xcode 已經默認將release環境下的斷言取消了, 免除了忘記關閉斷言造成的程序不穩定.
NSAssertionHandler:自定義處理方法,程序不會直接崩潰
NSAssertionHandler實例是自動創建的,用於處理錯誤斷言。如果NSAssert和NSCAssert條件評估為錯誤,會向NSAssertionHandler實例發送一個表示錯誤的字符串。每個線程都有它自己的NSAssertionHandler實例。
自定義NSAssertionHandler的子類
- @interface MyAssertHandler : NSAssertionHandler
- @end
- #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];
實現這些以后,程序能夠獲得斷言失敗后的信息,但是程序有可能繼續運行,不會強制退出程序.
