Почему вывод консоли отображается неполным в Xcode 8/iOS 10?
NSLog на устройствах в iOS 10/Xcode 8, кажется, усекается? Зачем?
Ответ 1
Временное решение, просто переопределите все NSLOG
- printf
в глобальном файле заголовка.
#define NSLog(FORMAT, ...) printf("%s\n", [[NSString stringWithFormat:FORMAT, ##__VA_ARGS__] UTF8String]);
Ответ 2
В iOS 10 и Xcode 8 Apple переключилась с старого старого ASL
(системного журнала Apple) на новую систему ведения журнала под названием Unified logging
. NSLog
вызовы фактически делегируются новым API os_log
. (источник: https://developer.apple.com/reference/os/logging):
Внимание!
Унифицированное ведение журнала доступно в iOS 10.0 и более поздних версиях, macOS 10.12 и позже, tvOS 10.0 и более поздних версий, и watchOS 3.0 и более поздних версий, и заменяет ASL (Logger от Apple System) и API Syslog. Исторически журнал сообщения были записаны в определенные места на диске, например /etc/system.log. Единая система регистрации хранит сообщения в памяти и в хранилище данных, а не в текстовые файлы журнала.
и
Внимание!
Линии сообщений, превышающие максимальную длину сообщения, усекаются при сохранении системой ведения журнала. Полные сообщения отображается при использовании инструмента командной строки журнала для просмотра прямого потока Мероприятия. Однако имейте в виду, что потоковые данные журнала являются дорогостоящая деятельность.
Ограничение максимальной длины системных систем раскрывается в заголовке SDK как 1024 символа для форматированных переменных, как отмечено @Hot_Leaks (source: <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
App, или с проблемой, возникающей в не отладочных приложениях (например, приложение AppStore, запущенном на клиентском устройстве).
Расширение ответа xfdai на развернутые приложения
В развернутых приложениях/не-отладочных сборках нет способа увидеть либо NSLog
, либо printf
s.
Единственный способ отправить сообщения непосредственно в журнал устройства (к которому можно получить доступ с помощью Xcode → Window → Devices, Mac Console App или сторонних утилит, таких как deviceconsole) вызывает os_log
API (который является преемником ASL
, используемым с iOS 10).
Вот глобальный заголовочный файл, который я использую для переопределения NSLog
в качестве вызова _os_log_internal
на iOS 10:
#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 */
Ответ 3
Это iOS 10 только "функция". Используйте это вместо:
printf("%s", [logString UTF8String]);
Ответ 4
В iOS 10:
-
printf()
работает внутри консоли Xcode, но не работает в журнале консоли устройства. -
NSLog
обрезается в обоих местах.
То, что я делаю сейчас, это разбиение строк NSLog
на строки и запись каждой строки по отдельности.
- (void) logString: (NSString *) string
{
for (NSString *line in [string componentsSeparatedByCharactersInSet: [NSCharacterSet newlineCharacterSet]])
{
NSLog(@"%@", line);
}
}
Это работает на консоли, но читать нелегко.
Ответ 5
Вы можете использовать этот метод. Разделить каждые 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);
}
}