如何禁用日志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.")