Swift のクロージャーを AnyObject にキャストする

Swift プログラミング

Objective-C との連携を視野に入れた時、Swift のクロージャーを AnyObject にキャストして使いたい場合が出てきます。

それを実現する方法を調べてみました。


Objective-C で設計された API の場合、引数でブロックを受け取るところが Swift からだと AnyObject! を受け取るように見える場合があります。Swift のクロージャーは AnyObject ではないため、このままだとクロージャーを API に渡すことができません。

Swift のクロージャーを AnyObject にキャストするには、次のように、クロージャーの型に @convention(block) 属性を付けて定義する必要があります。

let closure: @convention(block) (Int, Int) -> String = {

}

このようにすることで、このクロージャーは unsafeBitCast を使って AnyObject に変換できるようになる様子です。

let function: AnyObject = unsafeBitCast(closure, AnyObject.self)

あとは、これを Objective-C で作られた API の AnyObject! のところに渡してあげれば、Objective-C の API に Swift のクロージャーを渡して実行してもらうことが可能になります。

この @convention(block) を指定しないまま unsafeBitCastAnyObject にキャストした場合、実行時に EXC_BAD_INSTRUCTION 例外で強制終了される様子でした。