ポインタの配列を利用したい

投稿者: Anonymous
private var test1: Int = 0
private var test2: Int = 0
private var test3: Int = 0

private var testArray: [Int] {
    get {
       return [test1, test2, test3]
    }
}

上記とすることで配列定義できることを教えていただいたのですが、
ポインターの配列とすることはできないのでしょうか。
下記のようではだめでした。

private var testArray: [UnsafePointer<Int>] {
    get {
       return [&test1, &test2, &test3]
    }
}

解決

Swiftでは&記号は”address of”演算子ではなく、単にinoutパラメータであることを明示する(それによって関数呼び出しで値が変更される可能性があることをプログラマーに意識させるという効果があります)だけのもので、関数(メソッド含む)呼び出し以外では、ポインターを取得することはできません。

関数呼び出しなら良いんでしょということでこんな関数を使うことができるんですが、

    private var testArray: [UnsafePointer<Int>] {
        get {
            return withUnsafePointers(&test1, &test2, &test3) {
                test1Ptr, test2Ptr, test3Ptr in
                return [test1Ptr, test2Ptr, test3Ptr]
            }
        }
    }

基本的にwith…Pointer系の関数やメソッドではクロージャーにポインターとして渡される値はそのクロージャーを実行している間しか有効性が保障されないと考えるべきで、上記と全く同じコードが、test1, test2, test3の宣言された場所によっては全く期待通りに動かないこともあります。超要注意の記法で、どうしてもポインターでなければいけないという場合以外には使わないようにしてください。
(とは言ってもCやObjective-CのAPIを使おうと思うと「どうしてもポインター」と言う場合にはちょくちょく遭遇するんですが。とにかく「単にポインターを取り出すイディオム」的な軽い気持ちではwith...Pointerを使わないようにしてください。)

(追記)
コメントにあるaddObserverでのcontext引数の指定の仕方、最近のAppleのサンプルコードによく見られる形はこんなものです。(既にご存知かも知れませんが。)
グローバル変数として:

private var nantokaContext = 0 //当然Intになる
//...addObjserverに必要な数だけ繰り返し

同じファイルのとあるクラスのとあるメソッドの中:

        anObject.addObserver(self, forKeyPath: nantokaKey, options: [], context: &nantokaContext)
        //その他いろいろのaddObserverも同様

数が多くなるとこの部分をループにして、と思われるのも無理はありませんが、Appleのサンプルコードにはそんな例を見たことはありません。addObserverでのcontextの指定の仕方については、また興味と必要に応じて別件としてお尋ねください。

回答者: Anonymous

Leave a Reply

Your email address will not be published. Required fields are marked *