Our solution depends on two questions:
- Are we compiling using Xcode 8 and up? If yes, the new os_log is recognized. If not, we must fall back to existing NSLog behavior.
- Are we running under iOS-10 and up? If yes, we can use the new logger. If not, we must fall back to existing NSLog behavior.
We will find the answer to question [1] on compile time. For [2] we must test in runtime.
Here is the implementation:
mylog.h
//only used to force its +load() on app initialization
@interface MyLog:NSObject
@end
#if !__has_builtin(__builtin_os_log_format)
//pre Xcode 8. use NSLog
#else
//we need this include:
#import <os/log.h>
#endif
void myLog(NSString *format, ...);
#ifdef DEBUG
#define NSLog(f, ...) myLog(f, ## __VA_ARGS__)
#else
#define NSLog(f, ...) (void)0
#endif
mylog.m
@implementation MyLog
BOOL g_useNewLogger = NO;
+(void)load
{
NSOperatingSystemVersion os_ver = [[NSProcessInfo processInfo] operatingSystemVersion];
if (os_ver.majorVersion >= 10) {
g_useNewLogger = YES;
}
NSLog(@"Use new logger: %@", g_useNewLogger? @"YES":@"NO");
}
@end
void myLog(NSString *format, ...)
{
va_list args;
va_start(args, format);
#if !__has_builtin(__builtin_os_log_format)
//pre Xcode 8. use NSLog
NSLogv(format, args);
#else
//Xcode 8 and up
if (g_useNewLogger) { // >= iOS 10
NSString *nsstr = [[NSString alloc] initWithFormat:format arguments:args];
os_log(OS_LOG_DEFAULT, "%{public}s", [nsstr cStringUsingEncoding:NSUTF8StringEncoding]);
} else { // < iOS 10
NSLogv(format, args);
}
#endif
va_end(args);
}