我正在尝试向库中添加对新日志记录和事件跟踪 API 的支持,以便为尚未采用最新版本操作系统(iOS 或 macOS)的库用户保持向后兼容性.我正在为每个级别的日志记录定义自定义日志记录宏,然后为旧操作系统定义回退到 NSLog 。我已经完成了这项工作,但有一个问题。
如果您希望它们显示在日志输出中,新 API 要求您将任何非常量、非标量值显式标记为 public 。这就是我的宏调用的样子:
UZKLogInfo("Reading file %{public}@ from archive", fileName);
使用包含 os_log 的 SDK(例如 iOS 10.0 或更高版本)可以正常编译,但是当我使用早期版本编译时,我的宏会退回到 NSLog ,我收到编译器警告:
Using 'public' format specifier annotation outside of os_log()/os_trace()
打印出来的日志是这样的:
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 ,否则我会丢失调用站点元数据。
Best Answer-推荐答案 strong>
我选择在宏中进行 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);
关于ios - 在保持向后兼容性的同时采用 os_log API,我们在Stack Overflow上找到一个类似的问题:
https://stackoverflow.com/questions/45022233/
|