program tip

iOS 10 / Xcode 8의 장치에서 NSLog가 잘리는 것처럼 보입니까?

radiobox 2020. 11. 11. 19:41
반응형

iOS 10 / Xcode 8의 장치에서 NSLog가 잘리는 것처럼 보입니까? 왜?


콘솔 출력이 Xcode 8 / iOS 10에서 불완전한 것으로 표시되는 이유는 무엇입니까?

여기에 이미지 설명 입력


임시 해결책은 단지 모든 재정 NSLOGprintf글로벌 헤더 파일에.

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

iOS 10 및 Xcode 8에서 Apple은 오래된 ASL(Apple System Log)에서 Unified logging. NSLog실제로 호출은 새 os_logAPI에 위임됩니다 . (출처 : 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와 같은 디스크의 특정 위치에 기록되었습니다. 통합 로깅 시스템은 텍스트 기반 로그 파일에 쓰는 대신 메모리와 데이터 저장소에 메시지를 저장합니다.

중대한

시스템의 최대 메시지 길이보다 큰 로그 메시지 행은 로깅 시스템에 의해 저장 될 때 잘립니다. 로그 명령 줄 도구를 사용하여 실시간 활동 스트림을 볼 때 완전한 메시지가 표시됩니다. 그러나 스트리밍 로그 데이터는 비용이 많이 드는 작업입니다.

@Hot_Leaks (출처 :)에서 언급 한 바와 같이 "시스템의 최대 메시지 길이"제한은 SDK의 헤더에서 형식화 된 변수에 대해 1024 자로 표시됩니다 <os/log.h>.

/*!  
 * @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주위에 방법이 없지만 형식이 지정된 변수 ( %@) 대신 문자열 리터럴을 인쇄 하거나 형식이 지정된 문자열 변수를 <1024 문자열로 분할합니다.

printf디버거 (Xcode)가 프로세스의 출력 / 오류 스트림을 표시하므로 디버깅 중에 작동하지만 장치 로그 자체에는 전송되지 않습니다. 즉, xfdai의 솔루션은 macOS의 Console과 같은 다른 로그 응용 프로그램을 사용 하거나 디버깅되지 않은 응용 프로그램 (예 : 고객의 장치에서 실행되는 AppStore 응용 프로그램)에서 문제 가 발생할 때 도움이되지 않습니다 .


xfdai의 답변을 배포 된 애플리케이션으로 확장

배포 된 애플리케이션 / 디버그가 아닌 빌드에서는 NSLogs 또는 printfs 를 볼 수있는 방법이 없습니다 .

장치 로그 (Xcode-> Window-> Devices, mac의 콘솔 앱 또는 deviceconsole 과 같은 타사 유틸리티를 사용하여 액세스 할 수 있음)에 직접 메시지를 인쇄하는 유일한 방법 os_logAPI ( ASLiOS 10 이후 사용 된 후속 유틸리티 )를 호출 하는 것입니다. ).

다음 은 iOS 10 NSLog에서 호출로 재정의하는 데 사용하는 전역 헤더 파일입니다 _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 전용 "기능"입니다. 대신 사용 :

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

iOS 10 :

  1. printf() Xcode의 콘솔 내에서 작동하지만 장치의 콘솔 로그에서는 작동하지 않습니다.
  2. NSLog 두 곳 모두에서 잘립니다.

지금 제가하고있는 것은 NSLog문자열을 줄로 나누고 각 줄을 개별적으로 로깅하는 것입니다.

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

이것은 콘솔에서 작동하지만 읽기가 쉽지 않습니다.


이 방법을 사용할 수 있습니다. 800 자마다 분할합니다. 또는 설정할 수 있습니다. NSLOG 나는 1000 자마다 자른다 고 생각합니다. 문자열이 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);
            }

    }

참고 URL : https://stackoverflow.com/questions/39584707/nslog-on-devices-in-ios-10-xcode-8-seems-to-truncate-why

반응형