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

时间:2016-09-20 02:12:43

标签: ios objective-c xcode ios10 xcode8

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

enter image description here

7 个答案:

答案 0 :(得分:69)

临时解决方案,只需在全局头文件中重新定义所有NSLOGprintf

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

答案 1 :(得分:38)

在iOS 10&amp; Xcode 8,Apple从好的旧ASL(Apple系统日志)切换到名为Unified logging的新日志系统。实际上,NSLog次来电已委托给os_log新API <os/log.h>。 (来源:https://developer.apple.com/reference/os/logging):

  

重要

     

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

  

重要

     

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

&#34;系统的最大消息长度&#34;如@Hot_Leaks(来源:/*! * @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__) 所述),SDK标题中的限制显示为格式化变量的1024个字符:

libsystem_trace.dylib

由于缓冲区大小限制似乎硬编码到%@中,我看不到它的方法,但打印字符串文字而不是格式化变量(printf) ,或将格式化的字符串变量拆分为&lt; 1024个字符串。

Console将在调试期间工作,因为调试器(Xcode)显示进程的输出/错误流,但它不会被发送到设备日志本身。这意味着xfdai的解决方案在使用其他日志应用程序(如macOS的NSLog应用程序)时,或者在未调试的应用程序(例如AppStore应用程序)上出现问题时无法帮助您在客户的设备上运行。

扩展xfdai对已部署应用程序的回答

在已部署的应用程序/非调试版本中,无法查看printfos_log s。

将消息直接打印到设备日志的唯一方法(可以使用Xcode - &gt; Window - &gt;设备,mac的控制台应用程序或第三方实用程序,例如deviceconsole)进行访问正在调用ASL API(这是自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 */ 的调用的全局标题文件:

if (Double.IsNaN(YourValue) || Double.IsInfinity(YourValue))
{
    YourValue = 0;
}

答案 2 :(得分:9)

它只是iOS 10&#34;功能&#34;。请改用:

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

答案 3 :(得分:2)

在iOS 10上:

  1. printf()在Xcode的控制台中运行,但不能在设备的控制台日志中运行。
  2. NSLog会在这两个地方截断。
  3. 我现在正在做的是将我的NSLog字符串拆分成行并分别记录每一行。

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

    这适用于控制台,但不易阅读。

答案 4 :(得分:2)

您可以使用此方法。每800个字符分开。或者可以设置。 NSLOG我认为截断每1000个字符。 如果string小于800,则使用简单的NSLog。 这对于Json长字符串很有用并使用控制台。 printf使用Xcode调试窗口而非控制台。

    -(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);
            }

    }

答案 5 :(得分:0)

这不能提供很好的输出,但是即使在控制台上,也可以打印长日志的所有必要信息。

func Log(_ logString: String?) {
    if logString?.isEmpty ?? false { return }
    NSLog("%@", logString!)
    Log(String(logString!.dropFirst(1024)))
}

答案 6 :(得分:0)

从@xfdai答案中添加漂亮的功能和线条

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

带日期

#define NSLog(FORMAT, ...) printf("%s %s:%d %s\n", [[[NSDate date] description] UTF8String],__PRETTY_FUNCTION__,__LINE__,[[NSString stringWithFormat:FORMAT, ##__VA_ARGS__] UTF8String])