在Swift中向C函数表示NULL函数指针

考虑一下私有但尚未记录的Cocoa C函数_NSLogCStringFunction()_NSSetLogCStringFunction()_NSLogCStringFunction()返回一个函数指针,指向NSLog()幕后的Objective-C运行时使用的C函数, _NSSetLogCStringFunction()允许开发人员指定自己的C函数进行日志记录。 有关这两个函数的更多信息可以在此Stack Overflow问题和此WebObjects支持文章中找到 。

在C中,我可以传入NULL函数指针到_NSSetLogCStringFunction()

 extern void _NSSetLogCStringFunction(void(*)(const char*, unsigned, BOOL)); _NSSetLogCStringFunction(NULL); // valid 

但是,当我尝试在纯Swift中执行此操作时,我遇到了一些问题:

 /// Represents the C function signature used under-the-hood by NSLog typealias NSLogCStringFunc = (UnsafePointer, UInt32, Bool) -> Void /// Sets the C function used by NSLog @_silgen_name("_NSSetLogCStringFunction") func _NSSetLogCStringFunction(_: NSLogCStringFunc) -> Void _NSSetLogCStringFunction(nil) // Error: nil is not compatible with expected argument type 'NSLogCStringFunc' (aka '(UnsafePointer, UInt32, Bool) -> ()') 

如果我尝试使用unsafeBitCast绕过此编译时警告,我的程序只会崩溃EXC_BAD_INSTRUCTION (正如预期的那样,因为签名错误):

 let nullPtr: UnsafePointer = nil let nullFuncPtr = unsafeBitCast(nullPtr, NSLogCStringFunc.self) _NSSetLogCStringFunction(nullFuncPtr) // crash 

我如何表示一个NULL函数指针(void *)(void(*)(const char *, unsigned, BOOL)) / (UnsafePointer, UInt32, Bool) -> Void Swift中的(UnsafePointer, UInt32, Bool) -> Void

(Objective-)C声明的Swift映射

 extern void _NSSetLogCStringFunction(void(*)(const char*, unsigned, BOOL)); 

 public func _NSSetLogCStringFunction(_: (@convention(c) (UnsafePointer, UInt32, ObjCBool) -> Void)!) 

最简单的解决方案是将Objective-C extern声明放入Objective-C头文件中,并将其包含在桥接头中。

或者,在纯粹的Swift中它应该是

 typealias NSLogCStringFunc = @convention(c) (UnsafePointer, UInt32, ObjCBool) -> Void @_silgen_name("_NSSetLogCStringFunction") func _NSSetLogCStringFunction(_: NSLogCStringFunc!) -> Void 

在任何一种情况下,函数参数都是一个隐式解包的可选项,您可以使用nil调用它。 例:

 func myLogger(message: UnsafePointer, _ length: UInt32, _ withSysLogBanner: ObjCBool) -> Void { print(String(format:"myLogger: %s", message)) } _NSSetLogCStringFunction(myLogger) // Set NSLog hook. NSLog("foo") _NSSetLogCStringFunction(nil) // Reset to default. NSLog("bar") 

输出:

 myLogger:foo
 2016-04-28 18:24:05.492 prog [29953:444704]吧