/** NSAssert */ #if !defined(_NSAssertBody) #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) #endif
/** NSCAssert */ #if !defined(_NSCAssertBody) #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) #endif
/** NSParameterAssert */ #define NSParameterAssert(condition) NSAssert((condition), @"Invalid parameter not satisfying: %@", @#condition)
/** NSCParameterAssert */ #define NSCParameterAssert(condition) NSCAssert((condition), @"Invalid parameter not satisfying: %@", @#condition)
NSAssert
与 NSCAssert
用来处理一般情况的断言NSParameterAssert
与 NSCParameterAssert
用来处理参数化的断言NSAssert
与 NSCAssert
NSParameterAssert
与 NSCParameterAssert
NSAssertionHandler
是一个很直接的类,带有两个需要在子类中实现的方法:
-handleFailureInMethod:...
(当 NSAssert / NSParameterAssert 失败时调用)
-handleFailureInFunction:...
(当 NSCAssert / NSCParameterAssert 失败时调用)。
#pragram 第一步,创建一个继承自NSAssertionHandler 的类:LoggingAssertionHandler 用来专门处理断言 #import <Foundation/Foundation.h> @interface LoggingAssertionHandler : NSAssertionHandler @end #import "LoggingAssertionHandler.h" @implementation LoggingAssertionHandler /** 重写两个失败的回调方法,在这里执行我们想要抛出的错误(打印或者直接报错) */ - (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); NSException *e = [NSException exceptionWithName: NSStringFromSelector(selector) reason: format userInfo: nil]; @throw e; } - (void)handleFailureInFunction:(NSString *)functionName file:(NSString *)fileName lineNumber:(NSInteger)line description:(NSString *)format, ...{ NSLog(@"NSCAssert Failure: Function (%@) in %@#%li", functionName, fileName, (long)line); } @end
大部分情况下,你只需在
-application:didFinishLaunchingWithOptions:
中设置当前线程的断言处理器。
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { NSAssertionHandler *assertionHandler = [[LoggingAssertionHandler alloc] init]; [[[NSThread currentThread] threadDictionary] setValue:assertionHandler forKey:NSAssertionHandlerKey]; // ... return YES; }
#import "ViewController.h" @interface ViewController () @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; NSObject*mc = [NSObject new]; mc = @2; NSAssert(mc == nil, @"我不为空了"); } @end
2015-10-30 21:33:14.529 NSAssert[20537:678428] *** Terminating app due to uncaught exception 'viewDidLoad', reason: '我不为空了'
/** NSAssert */ #if !defined(_NSAssertBody) #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) #endif
/** 创建一个 preson 类 */ #import <Foundation/Foundation.h> typedef void(^mitchelBlock)(int num); @interface person : NSObject @property(nonatomic, copy)mitchelBlock block; @end #import "person.h" @implementation person - (instancetype)init{ if (self = [super init]) { dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ if (self.block) { self.block(1); } }); } return self; } @end /** ViewController 中的代码 */ #import "ViewController.h" #import "person.h" @interface ViewController () @property(nonatomic, strong)person * aPerson; @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; NSObject*mc = [NSObject new]; mc = @2; self.aPerson = [person new]; self.aPerson.block = ^(int num){ NSAssert(mc == nil, @"我不为空了"); 这里会有警告 NSLog(@"%d",num); }; } @end
NSCAssert
替换
NSAssert
,
NSCParameterAssert
来替换
NSParameterAssert
- (void)viewDidLoad { [super viewDidLoad]; NSObject*mc = [NSObject new]; mc = @2; self.aPerson = [person new]; self.aPerson.block = ^(int num){ NSCAssert(mc == nil, @"我不为空了"); NSCParameterAssert(num>5); }; }
NSAssert使用例子及讲解
NSAssert()只是一个宏,用于开发阶段调试程序中的Bug,通过为NSAssert()传递条件表达式来断定是否属于Bug,满足条件返回真值,程序继续运行,如果返回假值,则抛出异常,并切可以自定义异常描述。NSAssert()是这样定义的:
#define NSAssert(condition, desc)
condition是条件表达式,值为YES或NO;desc为异常描述,通常为NSString。当conditon为YES时程序继续运行,为NO时,则抛出带有desc描述的异常信息。NSAssert()可以出现在程序的任何一个位置。具体事例如下:
生成一个LotteryEntry对象时,传入的NSDate不能为nil,加入NSAssert()判断。对象初始化源码如下:
- (id)initWithEntryDate:(NSDate *)theDate { self = [super init]; if (self) { NSAssert(theDate != nil, @"Argument must be non-nil"); entryDate = theDate; firstNumber = (int)random() % 100 + 1; secondNumber = (int)random() % 100 + 1; } return self; }
接下来则是生成对象时传入一个值为nil的NSDate,看断言是否运行。
LotteryEntry *nilEntry = [[LotteryEntry alloc] initWithEntryDate:nil];
断言效果如下:
2013-01-17 20:49:12.486 lottery[3951:303] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Argument must be non-nil' *** First throw call stack:.......