JAL JAL - 1 year ago 70
Swift Question

Representing NULL Function Pointers to C Functions in Swift

Consider the private-yet-sort-of-documented Cocoa C functions

returns a function pointer to the C function used by the Objective-C runtime behind-the-scenes for
, and
allows developers to specify their own C function for logging. More information on both of these functions can be found in this Stack Overflow question and this WebObjects support article.

In C, I can pass in a NULL function pointer to

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

_NSSetLogCStringFunction(NULL); // valid

However, I'm running into some issues when I try to do this in pure 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
func _NSSetLogCStringFunction(_: NSLogCStringFunc) -> Void

_NSSetLogCStringFunction(nil) // Error: nil is not compatible with expected argument type 'NSLogCStringFunc' (aka '(UnsafePointer<Int8>, UInt32, Bool) -> ()')

If I try bypass this compile-time warning with
, my program just crashes with
(as expected, since the signature is wrong):

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

How do I represent a
function pointer to
(void *)
(void(*)(const char *, unsigned, BOOL))
(UnsafePointer<Int8>, UInt32, Bool) -> Void
in Swift?

Answer Source

The Swift mapping of the (Objective-)C declaration

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


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

The easiest solution would be to put the Objective-C extern declaration into an Objective-C header file and include that from the bridging header.

Alternatively, in pure Swift it should be

typealias NSLogCStringFunc = @convention(c) (UnsafePointer<Int8>, UInt32, ObjCBool) -> Void

func _NSSetLogCStringFunction(_: NSLogCStringFunc!) -> Void

In either case, the function parameter is an implicitly unwrapped optional, and you can call it with nil. Example:

func hookFunc(message: UnsafePointer<Int8>, _ length: UInt32, _ withSysLogBanner: ObjCBool) -> Void {

_NSSetLogCStringFunction(hookFunc) // Set NSLog hook.
_NSSetLogCStringFunction(nil) // Reset to default.