免费开源的iOS开发学习平台

NSLog()函数:2-定制输出日志的格式

当我们调用NSLog()来打印调试信息时,默认情况下,系统会按照固定的格式来展示相关的信息。但是在实际的开发过程中,我们往往希望得到更多、更加详细的信息,因此会涉及到对NSLog()函数进行输出日志的定制。

默认日志显示格式

在NSLog()中使用%@占位符来打印对象的功能是非常强大的,它不仅可以打印字符串、字典、数组等Foundation框架中已经定义的对象类型,我们自定义的对象类型也可以使用%@来打印。NSLog配合%@使用时,编译器会自动调用被打印对象的description属性的getter方法,如果打印的是类对象则调用类方法。

在NSObject类中, 有一个名为description的属性以及一个名为description的类方法,如下所示。

@property (readonly, copy) NSString *description;
+ (NSString *)description; //默认会打印该对象的类名和它在内存中的地址

我们新增一个Person类,并添加几个属性,然后实例化一个Person类对象,并打印对象信息,默认情况下,显示信息如下。

#import <Foundation/Foundation.h>
@interface Person : NSObject
@property (nonatomic, copy) NSString *name;
@property (nonatomic, copy) NSString *sex;
@property (nonatomic, assign) int age;
@end
#import <Foundation/Foundation.h>
#import "Person.h"

int main(int argc, const char * argv[]) {
    @autoreleasepool { 
        Person *p = [[Person alloc] init];
        p.name = @"jack";
        p.sex = @"man";
        p.age = 18;
        //打印对象信息
        NSLog(@"%@", p);
        NSLog(@"%@", [p class]);
    }
    return 0;
}

运行结果如下。我们可以看到,打印对象信息时,显示的是对象的类型+内存地址。打印类类型时,显示的是Person

重写description方法

当我们希望显示更加个性化的打印信息时,我们可以重写自定义类的description方法。如下所示, 我们在Person.m中添加如下代码。

#import "Person.h"
@implementation Person
//重写description属性的get方法
- (NSString *)description {
    return [NSString stringWithFormat:@"<Person: name: %@, sex: %@, age: %d>",
            self.name, self.sex, self.age];
}

//重写description类方法
+ (NSString *)description {
    return @"这是Person类";
}
@end

当我们再次运行之前的代码时,打印信息如下。

定制NSLog()打印的公共信息

默认情况下,使用NSLog打印出来的日志前面带有很长一串的时间戳,可能有时候我们根本用不到,而且还会影响查看的效率。其实对于NSLog的输出格式我们也是可以自定义的,只需要我们写一个宏定义就可以了。我们可以把如下宏定义放在程序运行环境中,即可改变NSLog()打印的公共信息,此时,打印的是调用NSLog()函数所在的文件以及行号。

#define NSLog(FORMAT, ...) fprintf(stderr,"%s:%d\t %s\n",[[[NSString stringWithUTF8String:__FILE__] lastPathComponent] UTF8String], __LINE__, [[NSString stringWithFormat:FORMAT, ##__VA_ARGS__] UTF8String]);

把上述代码添加到main.m中,再次运行,显示信息如下。

由于NSLog的运行效率比较低,所以在项目中非调试状态下(release)不应该出现大量的NSLog,所以有些时候我们会在项目的.pch文件(或者单独建立一个Macro.h文件管理所有的宏)中去定义一个宏,让调试函数只在调试版本(Debug)中生效,发布版本(Release)中就不能使用。

下方的代码段可以放在项目的宏定义文件中,也可以放在.pch文件中,添加后,打印日志只有在Debug模式下生效,Release模式不打印日志。

#ifdef DEBUG
#define NSLog(FORMAT, ...) fprintf(stderr,"%s:%d\t %s\n",[[[NSString stringWithUTF8String:__FILE__] lastPathComponent] UTF8String], __LINE__, [[NSString stringWithFormat:FORMAT, ##__VA_ARGS__] UTF8String]);
#else
#define NSLog(...)
#endif

示例代码

https://github.com/99ios/6.4.2