警告:这个答案使用私有但排序的 Cocoa C 函数_NSSetLogCStringFunction()
和_NSLogCStringFunction()
.
_NSSetLogCStringFunction()
是 Apple 创建的一个接口,用于处理NSLog
. 它最初是为 WebObjects 与NSLog
Windows 机器上的语句挂钩而公开的,但今天仍然存在于 iOS 和 OS X API 中。它记录在此支持文章中。
该函数接收一个带有参数的函数指针、const char* message
要记录的字符串、unsigned length
消息的长度和BOOL withSysLogBanner
切换标准日志记录横幅的 a。如果我们创建自己的日志钩子函数,它实际上不做任何事情(一个空的实现而不是fprintf
像NSLog
在幕后那样调用),我们可以有效地禁用您的应用程序的所有日志记录。
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中找到一个示例实现,它提供了一个接口来将块数组添加到任何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 中,您还可以选择忽略所有块参数而不使用hookFunc
如下:
_NSSetLogCStringFunction { _,_,_ in }
要使用 Objective-C 重新打开日志记录,只需NULL
作为函数指针传入:
_NSSetLogCStringFunction(NULL);
nil
使用 Swift 时情况略有不同,因为如果我们尝试传入或nil
指针(NULL
在 Swift 中不可用),编译器会抱怨类型不匹配。为了解决这个问题,我们需要访问另一个系统函数,_NSLogCStringFunction
以获取指向默认日志记录实现的指针,在禁用日志记录时保留该引用,并在我们想要重新打开日志记录时设置该引用。
我已经通过添加一个来清理这个的 Swift 实现NSLogCStringFunc
typedef
:
/// 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.")