iOS 10 / Xcode 8中的设备NSLog似乎截断? 为什么?

为什么控制台输出在Xcode 8 / iOS 10中显示不完整?

在这里输入图像描述

一个临时解决scheme,只需重新定义全局NSLOG到全局头文件中的printf

 #define NSLog(FORMAT, ...) printf("%s\n", [[NSString stringWithFormat:FORMAT, ##__VA_ARGS__] UTF8String]); 

在iOS 10&Xcode 8中,Apple从良好的旧ASL (Apple System Log)切换到一个名为Unified logging的新日志logging系统。 实际上, NSLog调用委托给新的os_log API。 (来源: https : //developer.apple.com/reference/os/logging ):

重要

统一日志logging适用于iOS 10.0及更高版本,macOS 10.12及更高版本,tvOS 10.0及更高版本和watchOS 3.0及更高版本,并取代ASL(Apple System Logger)和Syslog API。 历史上,日志消息被写入到磁盘上的特定位置,例如/etc/system.log。 统一日志系统将消息存储在内存和数据存储中,而不是写入基于文本的日志文件。

重要

大于系统最大消息长度的日志消息行在日志系统存储时被截断。 使用日志命令行工具查看实时活动stream时,可以看到完整的消息。 但请记住,stream式日志数据是一项昂贵的活动。

如“@Hot_Leaks”(source: <os/log.h> )所示,SDK的头文件中显示“系统的最大消息长度”限制为1024个字符的格式化variables。

 /*! * @function os_log * * ... * * There is a physical cap of 1024 bytes per log line for dynamic content, * such as %s and %@, that can be written to the persistence store. * All content exceeding the limit will be truncated before it is * written to disk. * * ... * */ #define os_log(log, format, ...) os_log_with_type(log, OS_LOG_TYPE_DEFAULT, format, ##__VA_ARGS__) 

由于缓冲区大小的限制似乎是硬编码到libsystem_trace.dylib ,我没有看到一个方法,而是打印一个string文字,而不是一个格式化的variables( %@ ),或分割格式化的stringvariables<1024string。

printf将在debugging过程中工作,因为debugging器(Xcode)显示进程的输出/错误stream,但是它不会被发送到设备日志本身。 这意味着xfdai的解决scheme在使用其他日志应用程序(如macOS的Console应用程序)时,或者在未debugging的应用程序(例如在客户设备上运行的AppStore应用程序)上出现问题时不会对您有所帮助。


将xfdai的答案扩展到部署的应用程序

在已部署的应用程序/非debugging版本中,无法查看NSLogprintf

将消息直接打印到设备日志(可以使用Xcode – > Window – >设备,Mac的控制台应用程序或第三方实用程序,如deviceconsole访问 )的os_log是调用os_log API(这是ASL的后继版本iOS 10)。

这里是我用来重新定义NSLog的一个全局头文件,在iOS 10上调用_os_log_internal

 #ifndef PrefixHeader_pch #define PrefixHeader_pch #ifdef __OBJC__ #import <UIKit/UIKit.h> #import <Foundation/Foundation.h> #endif #import <os/object.h> #import <os/activity.h> /* * System Versioning Preprocessor Macros */ #define SYSTEM_VERSION_EQUAL_TO(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedSame) #define SYSTEM_VERSION_GREATER_THAN(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedDescending) #define SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedAscending) #define SYSTEM_VERSION_LESS_THAN(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedAscending) #define SYSTEM_VERSION_LESS_THAN_OR_EQUAL_TO(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedDescending) // os_log is only supported when compiling with Xcode 8. // Check if iOS version > 10 and the _os_log_internal symbol exists, // load it dynamically and call it. // Definitions extracted from #import <os/log.h> #if OS_OBJECT_SWIFT3 OS_OBJECT_DECL_SWIFT(os_log); #elif OS_OBJECT_USE_OBJC OS_OBJECT_DECL(os_log); #else typedef struct os_log_s *os_log_t; #endif /* OS_OBJECT_USE_OBJC */ extern struct os_log_s _os_log_default; extern __attribute__((weak)) void _os_log_internal(void *dso, os_log_t log, int type, const char *message, ...); // In iOS 10 NSLog only shows in device log when debugging from Xcode: #define NSLog(FORMAT, ...) \ if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"10.0")) {\ void(*ptr_os_log_internal)(void *, __strong os_log_t, int, const char *, ...) = _os_log_internal;\ if (ptr_os_log_internal != NULL) {\ _Pragma("clang diagnostic push")\ _Pragma("clang diagnostic error \"-Wformat\"")\ _os_log_internal(&__dso_handle, OS_OBJECT_GLOBAL_OBJECT(os_log_t, _os_log_default), 0x00, [[NSString stringWithFormat:FORMAT, ##__VA_ARGS__] UTF8String]);\ _Pragma("clang diagnostic pop")\ } else {\ NSLog(FORMAT, ##__VA_ARGS__);\ }\ } else {\ NSLog(FORMAT, ##__VA_ARGS__);\ } #endif /* PrefixHeader_pch */ 

这是一个iOS 10的“function”。 用这个代替:

 printf("%s", [logString UTF8String]); 

在iOS 10上:

  1. printf()在Xcode的控制台中工作,但不能在设备的控制台日志中工作。
  2. NSLog截断在两个地方。

我现在正在做的是将我的NSLogstring拆分成行并单独logging每行。

 - (void) logString: (NSString *) string { for (NSString *line in [string componentsSeparatedByCharactersInSet: [NSCharacterSet newlineCharacterSet]]) { NSLog(@"%@", line); } } 

这在控制台上工作,但不容易阅读。

你可以使用这个方法。 每800个字符拆分。 或者可以设置。 NSLOG我认为截断每1000个字符。 如果string小于800,将使用简单的NSLog。 这对于Json长string和使用控制台很有用。 printf使用Xcodedebugging窗口而不是控制台。

– (void)JSLog:(NSString *)logString {

  int stepLog = 800; NSInteger strLen = [@([logString length]) integerValue]; NSInteger countInt = strLen / stepLog; if (strLen > stepLog) { for (int i=1; i <= countInt; i++) { NSString *character = [logString substringWithRange:NSMakeRange((i*stepLog)-stepLog, stepLog)]; NSLog(@"%@", character); } NSString *character = [logString substringWithRange:NSMakeRange((countInt*stepLog), strLen-(countInt*stepLog))]; NSLog(@"%@", character); } else { NSLog(@"%@", logString); } }