【发布时间】:2017-12-14 18:56:36
【问题描述】:
我正在尝试向库中添加对新日志记录和活动跟踪 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,否则我会丢失调用站点元数据。
【问题讨论】:
-
“某种字符串替换”听起来您已经回答了自己的问题。你看过
NSString提供了哪些方法吗? -
@CRD 但是我想要替换的不是
NSString,而是来自源文件的文本,它被放入宏中——它不是内存中分配的对象。我不确定预处理器有哪些可用的工具,但我认为我没有办法使用NSString上的方法。 -
您的
@format是NSString,不管该字符串是编程生成的还是文字,它仍然是NSString。您可能无法在编译期间更改字符串,但您可以在运行时更改它。您的宏包含对NSLog的调用,它可以包含方法调用。 -
@CRD 现在我明白了你的建议,但我正在寻找编译时解决方案。不过,我认为添加
NSString替换可以作为最后的手段。 -
编译时解决方案是更改代码文件上的文件扩展名,例如
.myExt,并在Xcode 中为.myExt添加构建规则。然后,构建规则将.myExt处理为.m,删除不需要的{public},然后编译器处理.m。构建规则是一个脚本,它可以调用任何命令行应用程序等来完成它的工作。 Apple 有(曾经有?)一个使用 Ruby 脚本预处理字符串文件的示例,您也许可以对其进行调整。或者您可以在宏中包含NSString方法,运行时成本可能微不足道。
标签: ios objective-c macos logging macros