2016-04-28 3 views
8

Рассмотрим функции Cocoa C private-yet-sort-of-documented _NSLogCStringFunction() и _NSSetLogCStringFunction(). _NSLogCStringFunction() возвращает указатель на функцию C, используемую во время выполнения Objective-C за кадром для NSLog(), а _NSSetLogCStringFunction() позволяет разработчикам указывать собственную функцию C для ведения журнала. Более подробную информацию о обеих этих функциях можно найти в this Stack Overflow question и this WebObjects support article.Представление указателей функций NULL для функций C в Swift

В 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<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?

+3

лол, мгновенная downvote по какой-либо причине - не было даже времени, чтобы прочитать весь вопрос. – luk2302

+1

@ luk2302 Угадайте, у меня есть фанат :) Это новый рекорд для меня, -1 через 44 секунды. – JAL

ответ

5

Свифт отображение (C) объективно-декларации

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

является

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

Самым простым решением было бы поставить Objective-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 
+0

Ух, правда? Все, что мне нужно было сделать, это изменить 'Bool' на' ObjCBool'? -_- В Swift слишком много типов Bool. Спасибо Мартину. – JAL

+0

@JAL: «@convention (c)» и неявно развернутый параметр. –

+0

На самом деле, я не думаю, что «ObjCBool» требуется. Похоже, мне просто не хватало '@convention (C)' и неявно развернутый параметр. Использование 'Bool' с двумя другими, кажется, работает. Вы видите то же самое? – JAL

Смежные вопросы