iOS 关于log输出

一个常用的宏

#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);

然而,在自定义的类上这么做,那么输出的信息却是下面这样:


上面的内容明显满足不了我们的渴求,只有类名和地址,而强大的我们需求的应该更多()

要想输出更为爽快的也简单,只需覆写description方法。例如,下面这个代表个人信息的类:

#import 

@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);
//

但是,一旦属性很多这样写就有点坏味道了,我们通常在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)
              }];
    
}

输出结果如下:


(lldb) po person

再插一嘴,如果你的控制台打印酱婶

(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模式。别问我咋知道的

你可能感兴趣的:(iOS 关于log输出)