Swift3のポインタの実践編

主にSwiftのポインタとCのポインタとの対比やポインタの変換方法についてのまとめ

Swiftでのポインタの基礎については基礎編を参照

Cのポインタとの対比

Hogeという型のポインタを表す場合

Swift C
UnsafePointer<Hoge> const Hoge*
UnsafeMutablePointer<Hoge> Hoge*

void*(汎用ポインタ)には専用の型が用意されている

Swift C
UnsafeRawPointer const void*
UnsafeMutableRawPointer void*

なお、ポインタ経由で値を変更したい場合はMutableがついている方を、参照のみであればついていない方を使う

ポインタへの変換方法

早見表

変換元 Hoge UnsafePointer UnsafeRawPointer
Hoge - 1.withUnsafePointer 1 -> 3
UnsafePointer 2.pointee or [] - 3.UnsafeRawPointer()
UnsafeRawPointer 4 -> 2 4.assumingMemoryBound -

Mutableの場合も変換方法は同じであるが、それぞれMutableに対応したものを使う

HogeからUnsafeRawPointerのように直接変換できる方法がない場合は、 UnsafePointerに変換してから目的の型へ2段階で変換する

異なる型同士での変換については基礎編を参照のこと

コード例

前提として、Hogeは以下の型とする

struct Hoge {
    var x: Float, y: Float, z: Float
}

(今回は構造体だが、実体がプリミティブでもクラスでも方法は同じ)

1.2. Hoge => Unsafe(Mutable)Pointer => Hoge

Hogeをポインタへ変換、変換したポインタ経由で元のHogeにアクセスする場合

Cの書き方

Hoge pos;
pos.x = pox.y = pos.z = 1;

Hoge* p = &pos;
p->x = 100;             // pos.x = 100 となる
(*p).y = 200;           // pos.y = 200 となる

Swiftの書き方

var pos = Hoge(x: 1, y: 1, z: 1)
withUnsafeMutablePointer(to: &pos) { 
    let p: UnsafeMutablePointer<Hoge> = $0
    p.pointee.x = 100   // pos.x = 100 となる
    p.pointee.y = 200   // pos.y = 200 となる
}
// または以下でも同じ
withUnsafeMutablePointer(to: &pos) { p in
    // p が UnsafeMutablePointer<Hoge> となる
}

withUnsafe(Mutable)Pointerのクロージャは値を返せるからといって

let p = withUnsafeMutablePointer(to: &pos) { $0 }   // 絶対ダメ
p.pointee.x = 100

というようにポインタを返す書き方は禁止。 渡されるポインタが有効なのはクロージャ内だけなので、上記書き方の動作は未定義である

よって、クロージャ内で処理を完結させるか、Swiftの変数に代入(値コピー)してそれを返すこと

3. Unsafe(Mutable)Pointer => Unsafe(Mutable)RawPointer

Cの書き方

// pHoge が Hoge* の場合
void* pRaw = (void*)pHoge;

Swiftの書き方

// pHoge が UnsafePointer<Hoge> の場合
let pRaw = UnsafeRawPointer(pHoge)

4. Unsafe(Mutable)RawPointer => Unsafe(Mutable)Pointer

Cの書き方

// pRaw が void* の場合
Hoge* pHoge = (Hoge*)pRaw;

Swiftの書き方

// pRaw が UnsafeRawPointer の場合
let pHoge = pRaw.assumingMemoryBound(to: Hoge.self)

ただし、pRawが既にバインド済であることが前提
未バインドの場合は、bindMemoryを使う

参考リンク