标签:
每个线程拥有它自己的断言处理器,它是 NSAssertionHandler 类的实例对象。当被调用时,一个断言处理器打印一条包含方法和类名(或者函数名)的错误信息。然后它抛出一个 NSInternalInconsistencyException 异常。
/** 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
Pay Attension:
据说,许多经验丰富的 Objective-C 开发者们告诫不要在生产环境中使用 NSAssertionHandler。基础类库中的断言处理是用来在一定安全距离外来理解和感激的。请小心行事如果你决定在对外发布版的应用中使用它。
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
这样我们就会看到 Block 中循环引用的警告啦: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);
};
}
标签:
原文地址:http://www.cnblogs.com/W-Kr/p/5327532.html