我正在尝试将新的日志记录和活动跟踪API的支持添加到库中,以便为尚未采用最新版本操作系统(iOS或macOS)的库的用户保持向后兼容性。我正在为每个级别的日志记录定义自定义日志记录宏,然后对于较旧的操作系统,则回退到NSLog
。我有这个问题,有一个问题。
如果您希望它们显示在日志输出中,则新API要求您将任何非常量非标量值标记为显式public
。这就是我的宏的调用:
UZKLogInfo("Reading file %{public}@ from archive", fileName);
这适用于包含os_log
的SDK(例如iOS 10.0或更高版本),但是当我使用早期版本编译以便我的宏回退到NSLog
时,我收到编译器警告:
在os_log()/ os_trace()之外使用'public'格式说明符注释
打印的日志行如下所示:
Reading file <decode: missing data> from archive
这是我的宏定义的简化版本(仅包括info
定义并简化了条件:
#if UNIFIED_LOGGING_SUPPORTED
@import os.log;
#define UZKLogInfo(format, ...) os_log_info(OS_LOG_DEFAULT, format, ##__VA_ARGS__);
#else // Fall back to regular NSLog
#define UZKLogInfo(format, ...) NSLog(@format, ##__VA_ARGS__);
#endif
有没有办法在后备情况下从format
删除“{public}”文本(某种字符串替换?)?或者是否有另一种方法来支持旧的和新的API而不放弃我在日志中总是显示的信息级别?我需要使用宏(根据last year's WWDC session on the topic,否则我将丢失呼叫站点元数据。
答案 0 :(得分:2)
我选择在宏中执行NSString
替换,并将编译器警告作为其中的一部分进行抑制,因此可以为每一行完成,而不是对整个文件或项目进行全局操作。它看起来像这样:
#if UNIFIED_LOGGING_SUPPORTED
@import os.log;
#define UZKLogInfo(format, ...) os_log_info(OS_LOG_DEFAULT, format, ##__VA_ARGS__);
#else // Fall back to regular NSLog
#define _removeLogFormatTokens(format) [@format stringByReplacingOccurrencesOfString:@"{public}" withString:@""]
#define _stringify(a) #a
#define _nsLogWithoutWarnings(format, ...) \
_Pragma( _stringify( clang diagnostic push ) ) \
_Pragma( _stringify( clang diagnostic ignored "-Wformat-nonliteral" ) ) \
_Pragma( _stringify( clang diagnostic ignored "-Wformat-security" ) ) \
NSLog(_removeLogFormatTokens(format), ##__VA_ARGS__); \
_Pragma( _stringify( clang diagnostic pop ) )
#define UZKLogInfo(format, ...) _nsLogWithoutWarnings(format, ##__VA_ARGS__);
#endif
它的召唤如下:
UZKLogInfo("Message: %@", anObjectToLog);