Представление указателей нулевой функции на функции 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