Представление указателей нулевой функции на функции C в Swift

рассмотрим частные, но-вроде-документированные функции Cocoa c _NSLogCStringFunction() и _NSSetLogCStringFunction(). _NSLogCStringFunction() возвращает указатель на функцию C, используемую средой выполнения Objective-C за кулисами для NSLog() и _NSSetLogCStringFunction() позволяет разработчикам указывать свою собственную функцию C для ведения журнала. Более подробную информацию об обеих этих функциях можно найти в этот вопрос переполнения стека и эта статья поддержки WebObjects.

в C, я могу пройти в a Указатель нулевой функции на _NSSetLogCStringFunction():

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

_NSSetLogCStringFunction(NULL); // valid

тем не менее, я сталкиваюсь с некоторыми проблемами, когда пытаюсь сделать это в 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
@_silgen_name("_NSSetLogCStringFunction")
func _NSSetLogCStringFunction(_: NSLogCStringFunc) -> Void

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

если я попытаюсь обойти это предупреждение времени компиляции с unsafeBitCast моя программа просто вылетает с EXC_BAD_INSTRUCTION (как и ожидалось, поскольку подпись неправильная):

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

как я представляю NULL указатель на функцию (void *) или (void(*)(const char *, unsigned, BOOL))/(UnsafePointer<Int8>, UInt32, Bool) -> Void в Swift?

1 ответов


быстрое отображение декларации (Objective-)C

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

is

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

самым простым решением было бы поставить цель-C extern объявление в файл заголовка Objective - C и включает это из мостового коллектора.

альтернативно, в чистом Swift это должно быть

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

@_silgen_name("_NSSetLogCStringFunction")
func _NSSetLogCStringFunction(_: NSLogCStringFunc!) -> Void

в любом случае, параметр функция неявно развернул необязательно, и вы можете назвать это с nil. Пример:

func myLogger(message: UnsafePointer<Int8>, _ 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] bar