The Pragmatic Ball boy

iOSを中心にやってる万年球拾いの老害エンジニアメモ

Swiftで引数リスト(CVaListPointer)の渡し方

SwiftからObjective-Cメソッドを呼ぶ際に、引数が引数リスト(va_list)の場合、Swiftでは型が以下のようなCVaListPointerになります。

class func raise(_ name: String,
          format format: String,
      arguments argList: CVaListPointer)

結論からいきますと、getVaListという関数を使って、getVaListの引数に引数リストとして渡したいArrayを突っ込めばよいです。

NSException.raise("hoge exception", format:"exception raised %d", arguments:getVaList([1]))





以下脱線

CVaListPointerの定義を調べてみるとこのようになるほどわからん感じの構造体です。

/// The corresponding Swift type to `va_list` in imported C APIs.
struct CVaListPointer {
    init(_fromUnsafeMutablePointer from: UnsafeMutablePointer<Void>)
}

CVaListPointerを生成するためのメソッドが用意されていてこれを使う。

/// Returns a `CVaListPointer` built from `args` that's backed by
/// autoreleased storage.
///
/// .. Warning:: This function is best avoided in favor of
///    `withVaList`, but occasionally (i.e. in a `class` initializer) you
///    may find that the language rules don't allow you to use
///    `withVaList` as intended.
func getVaList(args: [CVarArgType]) -> CVaListPointer

CVarArgTypeはprotocol

protocol CVarArgType {

    /// Transform `self` into a series of machine words that can be
    /// appropriately interpreted by C varargs
    func encode() -> [Word]
}

ということからgetVaListの引数には、CVarArgTypeプロトコルを実装しているクラスのArrayということになります。

Intなどの型はCVarArgTypeをextensionで実装してるので使えます。

extension Int : CVarArgType {

    /// Transform `self` into a series of machine words that can be
    /// appropriately interpreted by C varargs
    func encode() -> [Word]
}

調べた感じだとStringは一見CVarArgTypeを実装していないように見えるんですが、ArrayにString入れても使えるのはなんでかな・・