在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]吧