在宏中使用 Objective C API 登录静态库

Posted

技术标签:

【中文标题】在宏中使用 Objective C API 登录静态库【英文标题】:Using Objective C API in Macro to Log in static lib 【发布时间】:2016-01-27 12:27:54 【问题描述】:

我想做这样的事情,但在第一个“if”时出错。

#if ([[[NSProcessInfo processInfo] arguments] containsObject:@"-com.myproj.MyLibDebug"])
#define DLog(fmt, ...) NSLog((@"%s [Line %d] " fmt), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__)
#else
#define DLog(...) /* */
#endif

如何使用宏来使用它?是否可以在 Objective C 中编写这样的表达式?

或者做一些更高级的事情,比如 在参数数组中获取-com.myproj.MyLibDebug 的下一个值,然后根据值将调试日志级别设置为 4 或 8。

从构建配置(方案)传递的参数是

-com.myproj.MyLibDebug 4

【问题讨论】:

任何反对票都应该解释。 【参考方案1】:

我会反过来,将定义基于 if() 结果。

#define DLog(fmt, ...)  if ([[[NSProcessInfo processInfo] arguments] containsObject:@"-com.myproj.MyLibDebug"]) \
....\
 else \

#if 是基于宏的,它不能使用动态值

【讨论】:

...所以问题是什么?混合编译时和运行时元素?您还愿意评论一下该宏所产生的费用吗? 是的,问题是宏是在编译时评估的,而不是在运行时评估的,因此无法对参数数组进行评估。至于复杂性/时间开销,预处理器将使用if() 块更改每次出现的DLog()。不过,我不是宏观问题的专家。 谢谢。这似乎更好或将起作用。但要获得这些值,我最好有一个新的 Logger 类,它将解码和使用 NSLog。这个问题然后我可以打印出消息,但松开 LINEFILE 宏。不是吗? 您可以使用将_LINE__FILE_ 用作参数的宏。我建议你看看 cocoalumberjack 来处理日志部分,我发现它非常有用且可定制。【参考方案2】:

我不能使用 MACRO 进行这种日志记录,而是使用我自己的类来记录它,因为我必须从启动时传递的参数中解码运行时 logLevel。这是我的课。

头文件。

#import <Foundation/Foundation.h>

typedef NS_ENUM(NSUInteger, IDCLogFlag) 
    IDCLogFlagError     = (1 << 0),
    IDCLogFlagWarning   = (1 << 1),
    IDCLogFlagInfo      = (1 << 2),
    IDCLogFlagDebug     = (1 << 3),
    IDCLogFlagVerbose   = (1 << 4)
;

typedef NS_ENUM(NSUInteger, IDCLogLevel) 
    IDCLogLevelOff      = 0,
    IDCLogLevelError    = IDCLogFlagError,
    IDCLogLevelWarning  = IDCLogFlagError | IDCLogFlagWarning,
    IDCLogLevelInfo     = IDCLogLevelWarning | IDCLogFlagInfo,
    IDCLogLevelDebug    = IDCLogLevelInfo | IDCLogFlagDebug,
    IDCLogLevelVerbose  = IDCLogLevelDebug | IDCLogFlagVerbose,
    IDCLogLevelAll      = NSUIntegerMax
;

@interface IDCLogger : NSObject

/** Programmatically set the log level.*/
+ (void)setLogLevel:(int)l;

+(void)error:(NSString *)format, ... ;
+(void)warn:(NSString *)format, ... ;
+(void)info:(NSString *)format, ... ;
+(void)debug:(NSString *)format, ... ;
+(void)verbose:(NSString *)format, ... ;

@end

.m 文件

#import "IDCLogger.h"

static NSUInteger logLevel = IDCLogLevelError;

/** This argument should be passed from XCode's build scheme configuration option, Arguments passed on launch */
static const NSString *kIdcLogLevelArgument = @"-com.yourcompany.IDCLogLevel";

@implementation IDCLogger

+ (instancetype)sharedInstance 
    static id sharedInstance = nil;

    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^
        sharedInstance = [[self alloc] init];
    );

    return sharedInstance;


+(void)initialize

    NSArray *arguments = [[NSProcessInfo processInfo] arguments];
    NSUInteger value = 1;
    if ([arguments containsObject:kIdcLogLevelArgument]) 
        NSUInteger index = [arguments indexOfObject:kIdcLogLevelArgument];
        if (arguments.count > index) 
            NSString *valueStr = [arguments objectAtIndex:index + 1];
            NSCharacterSet* notDigits = [[NSCharacterSet decimalDigitCharacterSet] invertedSet];
            if ([valueStr rangeOfCharacterFromSet:notDigits].location == NSNotFound)
            
                value = [valueStr integerValue];
            
        
    

    logLevel = value;

//  NSUInteger exp = 0;
//  if (value > 0) 
//      exp = log2(value) + 1;
//  
//  logLevel = pow(2, exp);
//  NSLog(@"logLevel = %lu", (unsigned long)logLevel);


+ (void)setLogLevel:(int)l

    logLevel = l;
    NSLog(@"[%@] Log level set to: %i", [self class], l);


+(void)error:(NSString *)format, ... 
    if (logLevel >= IDCLogLevelError) 
        va_list args;
        va_start(args, format);
        [[self sharedInstance] logFormat:format withParameters:args];
        va_end(args);
    


+(void)warn:(NSString *)format, ... 
    if (logLevel >= IDCLogLevelWarning) 
        va_list args;
        va_start(args, format);
        [[self sharedInstance] logFormat:format withParameters:args];
        va_end(args);
    


+(void)info:(NSString *)format, ... 
    if (logLevel >= IDCLogLevelInfo) 
        va_list args;
        va_start(args, format);
        [[self sharedInstance] logFormat:format withParameters:args];
        va_end(args);
    


+(void)debug:(NSString *)format, ... 
    if (logLevel >= IDCLogLevelDebug) 
        va_list args;
        va_start(args, format);
        [[self sharedInstance] logFormat:format withParameters:args];
        va_end(args);
    


+(void)verbose:(NSString *)format, ... 
    if (logLevel >= IDCLogLevelVerbose) 
        va_list args;
        va_start(args, format);
        [[self sharedInstance] logFormat:format withParameters:args];
        va_end(args);
    


/** log the message formatted with status*/
-(void) log:(NSString*)format, ...

    va_list args;
    va_start(args, format);
    va_end(args);
    NSString *str = [[NSString alloc] initWithFormat:format arguments:args];
    NSLog(@"%@", str);
    [str release];


-(void) logFormat:(NSString *)format withParameters:(va_list)valist

    NSString *str = [[NSString alloc] initWithFormat:format arguments:valist];
    NSLog(@"%@", str);
    [str release];


@end

测试代码

- (void)testLogger

    [IDCLogger error:@"Error"];
    [IDCLogger warn:@"Warning"];
    [IDCLogger info:@"Info"];
    [IDCLogger debug:@"Debug"];
    [IDCLogger verbose:@"Verbose"];

    NSDate *d = [NSDate date];
    int i = 123;
    [IDCLogger error:@"Error with params. %i, %@", i, d];
    [IDCLogger warn:@"Warning with params. %i, %@", i, d];
    [IDCLogger info:@"Info with params. %i, %@", i, d];
    [IDCLogger debug:@"Debug with params. %i, %@", i, d];
    [IDCLogger verbose:@"verbose with params. %i, %@", i, d];

    [IDCLogger setLogLevel:0]; // no logging
    [IDCLogger error:@"Error with params. %i, %@", i, d];
    [IDCLogger warn:@"Warning with params. %i, %@", i, d];
    [IDCLogger info:@"Info with params. %i, %@", i, d];
    [IDCLogger debug:@"Debug with params. %i, %@", i, d];
    [IDCLogger verbose:@"verbose with params. %i, %@", i, d];

    [IDCLogger setLogLevel:UINT_MAX]; // All logging
    [IDCLogger error:@"Error with params. %i, %@", i, d];
    [IDCLogger warn:@"Warning with params. %i, %@", i, d];
    [IDCLogger info:@"Info with params. %i, %@", i, d];
    [IDCLogger debug:@"Debug with params. %i, %@", i, d];
    [IDCLogger verbose:@"verbose with params. %i, %@", i, d];

    [IDCLogger setLogLevel:IDCLogLevelDebug]; // value = 15, error, warn, info and debug log
    [IDCLogger error:@"Error with params. %i, %@", i, d];
    [IDCLogger warn:@"Warning with params. %i, %@", i, d];
    [IDCLogger info:@"Info with params. %i, %@", i, d];
    [IDCLogger debug:@"Debug with params. %i, %@", i, d];
    [IDCLogger verbose:@"verbose with params. %i, %@", i, d];

【讨论】:

以上是关于在宏中使用 Objective C API 登录静态库的主要内容,如果未能解决你的问题,请参考以下文章

Symfony 3在宏中使用宏?

MS Visual Studio 2010 C++ 预处理器 - 如果函数在宏中定义并在其他地方调用,未定义时是不是有任何开销

在宏中使用用户在表单中输入的信息

在宏中拆分字符串

在宏中过度使用会损害性能吗?

在宏中调用函数