SSブログ

ブロックのおかしな動作 [プログラミング]

前回完成した球面非球面のBezier曲線近似。思ったよりうまくできたので、さっそく会社の資料の中に入れた。先日それを会社の別の人が自分の資料のためにpdfからコピーしてぱわぽに貼った。それがなぜかZEMAXのビットマップよりぐにゃぐにゃして醜い。しかもたんなるpdfのビットマップスナップショットよりも汚い。縦横比も微妙におかしい。見せてもらってびっくりした。

ぱわぽってどうなってるんだ????おかしいんじゃないのか?

もう、ぱわぽでの問題はうんざりなので放っておくとして、OS Xのブロックでのおかしな動作について....

非球面を近似するためにはNewton法を使う。Newton法はずっと前書いた光線追跡のなかで、非球面と光線との交点を求めるのに使った。それを今回書き直した。最初に書いたとき(ほんの2年前のこと)、最小化する関数の値をデリゲートメソッドで計算するように書いたんだけど、ブロックを使うように書き換えた。ブロックにすることでNewton法を実行するクラスは読みやすくなった。そのコードはまた別途整理できたらいずれここで公開することにするが、おかしなことに出会った。

ブロックの中ではそれを取り囲んでいる関数やメソッドの自動変数(スタックの上の変数)を、ブロック内部でそのまま呼べるというのが便利なところ。でも、Objective-Cのメソッドの中でブロックを定義して、そのプロパティやインスタンス変数をブロック内部で呼ぶと自動的にselfに強い参照が発生する、とリファレンスにはある。さらっと書いてあるだけで、よく考えればオブジェクトの生存期間の制御のためには弱参照ではダメなので仕方ないんだけど、このせいで簡単に循環参照に陥ってみんな苦労している。例えばインスタンス変数も自動変数と同じように個別にブロックの構造体にコピーを作ればいい。そうすれば循環参照の問題はかなりすっきりする。

ところがそれでは解決できない問題がある。ブロック内部でメソッドを呼ぶ場合である。メソッドは隠れた引数としてselfポインタが渡されるので、結局メソッド呼び出しをサポートするためにはselfの強参照が必要になってしまう。もうこれは諦めるしかなくて、プログラマがなんらかの工夫(自動変数としてのオブジェクトが使うブロックでは、selfの弱い参照を持つポインタコピーをブロック内部では使うというのが一番簡単だけど、あまり美しくなし、ブロックの生存範囲が呼ばれるオブジェクトの部分集合でない場合は使えない)をしないといけない。

それはいいとして、おかしなことが起こった。ブロック内部で自分のメソッドではなく親クラスのメソッドを呼ぶ場合。つまり
- (void)aMethod
{
    void    (^aBlock)();
    aBlock = ^{
        [super aBaseClassMethod];
    };
}
というような場合。このブロックを実行するとこのaBaseClassMethodの内部では、なぜかselfポインタがnilになってしまう。もちろん
- (void)aMethod
{
    void    (^aBlock)();
    aBlock = ^{
        [self aBaseClassMethod];
    };
}
としても、文法上は許されるし、実際の動作としてもObjecitve-Cではselfであろうがsuperであろうがほとんど同じ(ランタイムでのメソッド検索の開始場所が違うだけ)なんだけど、この場合はちゃんとselfが渡されて実行できる。

Appleのドキュメントを探したんだけど、それらしい記述が見つからなくて、StackOverflowをあさってみると、似たようなことで悩んでる人を見つけた。解決としては同じことをするしかないようで、これはブロックの動作として絶対おかしい。コンパイラとRunTimeの仕事の切り分けがあやふやになったせいによる陥穽、という気がする。


nice!(0)  コメント(1)  トラックバック(0) 

nice! 0

コメント 1

Cialis 20mg

沒有醫生的處方
cialis dosage http://cialisvipsale.com/ Viagra or cialis
by Cialis 20mg (2018-04-14 07:38) 

コメントを書く

お名前:
URL:
コメント:
画像認証:
下の画像に表示されている文字を入力してください。

トラックバック 0

この広告は前回の更新から一定期間経過したブログに表示されています。更新すると自動で解除されます。