2016-04-28 28 views
8

文書化されているプラ​​イベート・ソート済みのCocoa C関数_NSLogCStringFunction()_NSSetLogCStringFunction()を考えてみましょう。 _NSLogCStringFunction()は、NSLog()のObjective-Cランタイムバックグラウンドで使用されるC関数への関数ポインタを返します。_NSSetLogCStringFunction()は、開発者が独自のC関数をログに指定できるようにします。これらの機能の詳細については、this Stack Overflow questionおよびthis WebObjects support articleを参照してください。 CではSwiftのC関数へのNULL関数ポインタの表現

、私は_NSSetLogCStringFunction()にNULL関数ポインタを渡すことができます。

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

_NSSetLogCStringFunction(NULL); // valid 

を私は純粋スウィフトでこれを実行しようとする場合しかし、私はいくつかの問題に実行しているよ:

/// 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 

Swiftの(void *)または(void(*)(const char *, unsigned, BOOL))/(UnsafePointer<Int8>, UInt32, Bool) -> VoidへのNULL関数ポインタを表すにはどうすればよいですか?

+3

笑、何らかの理由でインスタントdownvote - 全体の質問を読んでも、時間がありませんでした。 – luk2302

+1

@ luk2302私はファンがいると思う:)それは私のための新しい記録、44秒で-1です。 – JAL

答えて

5

(Objective-)C宣言のスイフトマッピング

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

最も簡単な解決策は、Objective-CのexternをObjective-Cのヘッダに 宣言を置くことであろう

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

ありますブリッジングヘッダーには が含まれています。

また、純粋スウィフト、それはいずれの場合も

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タイプが多すぎます。 Martinに感謝します。 – JAL

+0

@JAL: '@convention(c)'と暗黙的にアンラップされたパラメータ。 –

+0

実際、私は 'ObjCBool​​'が必要とは思わない。私がちょうど '@convention(C)'と暗黙のうちにラップされていないパラメータを欠いているように見えます。他の2つで 'Bool'を使うことはうまくいくようです。あなたは同じことを見ていますか? – JAL