如何禁用日志logging?
我有一个使用Apple提供的UITextChecker
类的应用程序。 这个类有一个错误:如果iOS设备处于脱机状态(预计通常是我的应用程序),每次我调用一些UITextChecker
的方法时,它将logging到控制台:
2016-03-08 23:48:02.119 HereIsMyAppName [4524:469877] UITextChecker sent string:isExemptFromTextCheckerWithCompletionHandler: to com.apple.TextInput.rdt but received error Error Domain=NSCocoaErrorDomain Code=4099 "The connection to service named com.apple.TextInput.rdt was invalidated."
我不希望有这个消息垃圾邮件。 有没有办法禁用代码日志logging? 在调用任何UITextChecker
的方法之前,我将禁用日志logging,然后重新启用它。 或者有没有什么办法如何有select地禁用日志select每个类(事件,如果它是基础类不是我的)? 还是其他解决scheme?
警告 :这个答案使用了私有的Cocoa C函数_NSSetLogCStringFunction()
和_NSLogCStringFunction()
。
_NSSetLogCStringFunction()
是由Apple创build的一个接口,用于处理NSLog
的实现函数。 它最初被暴露给WebObjects,以便挂接到Windows机器上的NSLog
语句,但是现在仍然存在于iOS和OS X API中。 这是支持文章中logging。
该函数接受一个函数指针,它的参数是const char* message
,要logging的string, unsigned length
,消息的长度,以及一个BOOL withSysLogBanner
来切换标准日志logging横幅。 如果我们为日志logging创build自己的钩子函数(实际上没有做任何事情(一个空的实现,而不是象NSLog
那样调用fprintf
),我们可以有效地禁用应用程序的所有日志logging。
Objective-C示例(或带桥接头的Swift):
extern void _NSSetLogCStringFunction(void(*)(const char*, unsigned, BOOL)); static void hookFunc(const char* message, unsigned length, BOOL withSysLogBanner) { /* Empty */ } // Later in your application _NSSetLogCStringFunction(hookFunc); NSLog(@"Hello _NSSetLogCStringFunction!\n\n"); // observe this isn't logged
这个例子的实现可以在YILogHook中find, YILogHook提供了一个向任何NSLog
语句添加块数组的接口(写入文件等)。
纯Swift示例:
@asmname("_NSSetLogCStringFunction") // NOTE: As of Swift 2.2 @asmname has been renamed to @_silgen_name func _NSSetLogCStringFunction(_: ((UnsafePointer<Int8>, UInt32, Bool) -> Void)) -> Void func hookFunc(message: UnsafePointer<Int8>, _ length: UInt32, _ withSysLogBanner: Bool) -> Void { /* Empty */ } _NSSetLogCStringFunction(hookFunc) NSLog("Hello _NSSetLogCStringFunction!\n\n"); // observe this isn't logged
在Swift中,你也可以select忽略所有的块参数而不使用hookFunc
如下所示:
_NSSetLogCStringFunction { _,_,_ in }
要使用Objective-C重新开启日志logging,只需将NULL
作为函数指针传入:
_NSSetLogCStringFunction(NULL);
对于Swift,情况有些不同,因为如果我们试图传递nil
或者一个nil
指针(在Swift中NULL
不可用),编译器会抱怨types不匹配。 为了解决这个问题,我们需要访问另一个系统函数_NSLogCStringFunction
来获取一个指向默认日志实现的指针,在禁用日志的时候保留这个引用,并且当我们想要重新开启日志function的时候设置引用。
我已经通过添加一个NSLogCStringFunc
typedef
清理了Swift实现:
/// Represents the C function signature used under-the-hood by NSLog typealias NSLogCStringFunc = (UnsafePointer<Int8>, UInt32, Bool) -> Void /// Sets the C function used by NSLog @_silgen_name("_NSSetLogCStringFunction") // NOTE: As of Swift 2.2 @asmname has been renamed to @_silgen_name func _NSSetLogCStringFunction(_: NSLogCStringFunc) -> Void /// Retrieves the current C function used by NSLog @_silgen_name("_NSLogCStringFunction") func _NSLogCStringFunction() -> NSLogCStringFunc let logFunc = _NSLogCStringFunction() // get function pointer to the system log function before we override it _NSSetLogCStringFunction { (_, _, _) in } // set our own log function to do nothing in an anonymous closure NSLog("Observe this isn't logged."); _NSSetLogCStringFunction(logFunc) // switch back to the system log function NSLog("Observe this is logged.")