一个常用的宏
#ifdef DEBUG
#define CustomLog(FORMAT, ...) do {\
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];\
[dateFormatter setDateStyle:NSDateFormatterMediumStyle];\
[dateFormatter setTimeStyle:NSDateFormatterShortStyle];\
[dateFormatter setDateFormat:@"HH:mm:ss:SSSS"];\
NSString *dateString = [dateFormatter stringFromDate:[NSDate date]];\
fprintf(stderr,"[%s:%d %s] %s\n", [[[NSString stringWithUTF8String:__FILE__] lastPathComponent] UTF8String], __LINE__, [dateString UTF8String], [[NSString stringWithFormat:FORMAT, ##__VA_ARGS__] UTF8String]);\
} while (0)
#else
#define CustomLog(FORMAT, ...) nil
#endif
- 它的作用精简系统的打印输出,省去了一大串没用的信息,比如年月日,项目名等等,让log更加清晰明了。
Q: do { ...} while(0)
是什么鬼,tell me why?
A: 当然是执行一次了,完美(😝开个玩笑)其实我以前用的就是不加do { ...} while(0)
感觉all in control
有一天看到了一篇文章提到下面这样写会报错
if (1)
CustomLog(@"%@",Fuck);
else{
}
原因很简单。当编译时宏替换后代码就变成这样了
if (1)
{\
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];\
[dateFormatter setDateStyle:NSDateFormatterMediumStyle];\
[dateFormatter setTimeStyle:NSDateFormatterShortStyle];\
[dateFormatter setDateFormat:@"HH:mm:ss:SSSS"];\
NSString *dateString = [dateFormatter stringFromDate:[NSDate date]];\
fprintf(stderr,"[%s:%d %s] %s\n", [[[NSString stringWithUTF8String:__FILE__] lastPathComponent] UTF8String], __LINE__, [dateString UTF8String], [[NSString stringWithFormat:FORMAT, ##__VA_ARGS__] UTF8String]);\
}) ;
else{
}
简单点
if (1){
NSLog(@"1");
};
else{
}
因为多出来的那个分号,会报错。So,为了严谨还是加do while
个人感觉这种情况很少见,一般人为了代码的可读性都不会省略花括号的,就算省略了也不会写这么一句log吧(砖友们在下眼界有限,尽管来喷)
再说descrription
调试程序时,经常需要打印查看对象信息,比如这样:
NSLog (@"object = %@", object);
然而,在自定义的类上这么做,那么输出的信息却是下面这样:
<WGPerson: 0x600000005bb0>
上面的内容明显满足不了我们的渴求,只有类名和地址,而强大的我们需求的应该更多(🤓)
要想输出更为爽快的也简单,只需覆写description方法。例如,下面这个代表个人信息的类:
#import <Foundation/Foundation.h>
@interface WGPerson : NSObject
@property(nonatomic,copy,readonly)NSString *personName;
@property(nonatomic,assign,readonly)NSUInteger personAge;
- (id)initWithPersonName:(NSString *)name
Age:(NSUInteger )age;
@end
@implementation WGPerson
-(id)initWithPersonName:(NSString *)name
Age:(NSUInteger)age
{
if ((self = [super init])) {
_personName = [name copy];
_personAge = age;
}
return self;
}
- (NSString *)description{
return [NSString stringWithFormat:@"<%@: %p, name:%@, age:%zd>",[self class], self, _personName, _personAge];
}
@end
输出就会变成这样
WGPerson *person =[[WGPerson alloc]initWithPersonName:@"Lily" Age:18];
NSLog(@"%@",person);
//<WGPerson: 0x600000032800, name:Lily, age:18>
但是,一旦属性很多这样写就有点坏味道了,我们通常在description方法中,把待打印的信息放到字典里面
- (NSString *)description{
return [NSString stringWithFormat:@"<%@: %p, %@>",
[self class],
self,
@{
@"personName":_personName,
@"personAge":@(_personAge)
}];
}
用NSDictionary来实现此功能可以令代码更容易维护:如果以后还要向类中新增属性,并且要在description方法中打印,那么只需要修改字典内容即可。
还有debugDescription
与description非常相似。区别在于,debugDescription是开发者在调试器中一控制台命令打印对象时才调用的。在NSObject类的默认实现中,此方法只是直接调用了description
也就是说,当你只覆写了description,此时NSLog的输出与你在lldb中po的是一样的
也许你只是想把某些属性放在Person对象的普通描述信息中,更详尽的内容放在调试的描述信息里,此时可用下列代码实现:
- (NSString *)description{
return [NSString stringWithFormat:@"<%@: %p, %@>",
[self class],
self,
@{
@"personName":_personName,
}];
}
-(NSString *)debugDescription{
return [NSString stringWithFormat:@"<%@: %p, %@>",
[self class],
self,
@{
@"personName":_personName,
@"personAge":@(_personAge)
}];
}
输出结果如下:
<WGPerson: 0x600000034100, {
personName = Lily;
}>
(lldb) po person
<WGPerson: 0x600000034100, {
personAge = 18;
personName = Lily;
}>
再插一嘴,如果你的控制台打印酱婶
(lldb) po person
error: Couldn't materialize: couldn't get the value of variable person: no location, value may have been optimized out
error: errored out in DoExecute, couldn't PrepareToExecuteJITExpression
你应该是在release模式。别问我咋知道的