唱吧开源库KTVHTTPCache学习(二)

  在学习唱吧开源库的时候,发现关于日志打印的宏定义写的特别的好,可以决定每个类是否打印日志,以及是否保存到log文件中。具体如下:

/**
 *  Log Enable Config
 */
#define KTVHCLogEnable(target, console_log_enable, record_log_enable)               \
static BOOL const KTVHCLog_##target##_ConsoleLogEnable = console_log_enable;        \
static BOOL const KTVHCLog_##target##_RecordLogEnable = record_log_enable;

#define KTVHCLogEnableValueConsoleLog(target)       KTVHCLog_##target##_ConsoleLogEnable
#define KTVHCLogEnableValueRecordLog(target)        KTVHCLog_##target##_RecordLogEnable

其中,关于宏定义中 ##的使用,我在网上找了一下,详细的解释如下:
原文地址:https://github.com/awesome-tips/iOS-Tips/blob/master/2017/12.md

宏中的 ## 的含义

作者: Lefe_x

在宏的定义中,我们也许会遇到过 ##,比如下面是一些第三方库中 ## 使用场景:

微信 WCDB 中的宏定义: #define __WCDB_BINDING(className) _s_##className##_binding

唱吧 KTVHTTPCache 定义不同类中是否可以打印的例子: #define KTVHCLogEnableValueConsoleLog(target) KTVHCLog_##target##_ConsoleLogEnable

那 ## 有什么用呢? ## 在宏中的作用就是先分隔,然后进行强制连接。我们可能会定义不同的函数名或变量时就可以使用这样的宏定义。

那 ## 是如何工作的呢?

__WCDB_BINDING(className) ,首先 _s_##className##_binding 会拆分成 _s,className ,_binding__WCDB_BINDING(ViewController) 将会被替换成 _s_ViewController_binding

KTVHCLogEnableValueConsoleLog(target),首先 KTVHCLog_##target##_ConsoleLogEnable 会被拆分为 KTVHCLog_, target 和 _ConsoleLogEnableKTVHCLogEnableValueConsoleLog(Lefex) 会被替换成 KTVHCLog_ Lefex_ConsoleLogEnable

3.当使用 KTVHCLogEnable(HTTPServer, YES) ,将会定义一个名为 KTVHCLog_ HTTPServer_ConsoleLogEnable 静态常量,初始值为 YES。

扫描二维码关注公众号,回复: 8836341 查看本文章
#define KTVHCLogEnable(target, console_log_enable)               \
static BOOL const KTVHCLog_##target##_ConsoleLogEnable = console_log_enable;        \

比如我们使用不同的 View 名字创建不同的 View:

#define Name(target) weibo_##target##_name
#define View(target) view##target##Label

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    NSString * Name(lefex) = @"Lefe_x";
    // 打印:You weibo name is: Lefe_x
    NSLog(@"You weibo name is: %@", weibo_lefex_name);
    
    UILabel *View(1) = [UILabel new];
    view1Label.backgroundColor = [UIColor redColor];
    
    UIView *View(2) = [UIView new];
    view2Label.backgroundColor = [UIColor yellowColor];
}

是谁调了我的底层库

作者: Lefe_x

调试的时候,往往底层库会埋一些 NSLog 来调试,使用下面这种方式打印出来的函数名称 __PRETTY_FUNCTION__ 是底层库的函数名。

#   define LEFLog(fmt, ...) NSLog((@"%s (%d) => " fmt), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__)

打印是这样的:+[Network post] 中打印了 I am a log,而不清楚是谁调用了。

+[Network post] (22) => I am a log

但是,我想要的是我在最顶层调用时的函数名,这样我可以很容易的看到是那个方法调用了底层库。

不太理解?举个例子吧: 每个 APP 都会有一个网络层,业务层会直接与网络层进行交互。调试的时候,我想知道 A 请求是在哪个页面中的哪个函数被调用了,咋么办?前提是 NSLog 在底层库。我们可以这样实现:

@implementation LEFLog
+ (NSString *)lastCallMethod
{
    NSArray *symbols = [NSThread callStackSymbols];
    NSInteger maxCount = symbols.count;
    NSString *secondSymbol = maxCount > 2 ? symbols[2] : (maxCount > 1 ? symbols[1] : [symbols firstObject]);
    if (secondSymbol.length == 0) {
        return @"";
    }
    
    NSString *pattern = @"[+-]\\[.{0,}\\]";
    NSError *error;
    NSRegularExpression *express = [NSRegularExpression regularExpressionWithPattern:pattern options:kNilOptions error:&error];
    if (error) {
        NSLog(@"Error: %@", error);
        return @"";
    }
    
    NSTextCheckingResult *checkResult = [[express matchesInString:secondSymbol options:NSMatchingReportCompletion range:NSMakeRange(0, secondSymbol.length)] lastObject];
    NSString *findStr = [secondSymbol substringWithRange:checkResult.range];
    return findStr ?: @"";
}

@end

然后定义一个宏:

#   define LEFLog(fmt, ...) NSLog((@"%@, %s (%d) => " fmt), [LEFLog lastCallMethod], __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__

打印结果是这样的:在 LefexViewController 中的 viewDidLoad 调用了 Network 的 post 方法,并打印 I am a log.

-[LefexViewController viewDidLoad], +[Network post] (22) => I am a log

更多优质文章,可以微信扫码关注:
这里写图片描述

发布了231 篇原创文章 · 获赞 110 · 访问量 60万+

猜你喜欢

转载自blog.csdn.net/HHL110120/article/details/95162464