一時的な解決策は、すべてのNSLOG
をグローバルヘッダーファイルのprintf
に再定義するだけです。
#define NSLog(FORMAT, ...) printf("%s\n", [[NSString stringWithFormat:FORMAT, ##__VA_ARGS__] UTF8String]);
IOS 10およびXcode 8では、Apple古き良きASL
(Appleシステムログ)からUnified logging
という新しいログシステムに切り替えられました。NSLog
呼び出しは実際に委任されます。新しいos_log
APIへ(ソース: 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(出典:<os/log.h>
)で示されているように、SDKのヘッダーでフォーマットされた変数の1024文字であることが明らかになっています。
/*!
* @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文字列に分割します。
デバッガー(Xcode)はプロセスのout/errorストリームを表示するため、printf
はデバッグ中に機能しますが、デバイスログ自体には送信されません。つまり、macOSのConsole
Appなどの他のログアプリケーションを使用する場合、またはデバッグされていないアプリケーション(顧客のデバイスで実行されるAppStoreアプリケーションなど)で問題が発生する場合、xfdaiのソリューションは役に立ちません。
デプロイされたアプリケーションへのxfdaiの答えの拡張
デプロイされたアプリケーション/非デバッグビルドでは、NSLog
sまたはprintf
sを表示する方法はありません。
メッセージをデバイスログに直接印刷する唯一の方法(Xcode->ウィンドウ->デバイス、macのコンソールアプリ、または deviceconsole などのサードパーティユーティリティを使用してアクセスできます)は、os_log
API(これはiOS 10以降で使用されているASL
の後継です。
IOS 10で_os_log_internal
への呼び出しとしてNSLog
を再定義するために使用しているグローバルヘッダーファイルを次に示します。
#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の場合:
printf()
はXcodeのコンソール内では機能しますが、デバイスのコンソールログでは機能しません。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);
}
}