きりかノート 3冊め

おあそびプログラミング

特異メソッドがいつのまにか使えなくなる?

このへんの話。今月この話題しかないから月のアーカイブでいいや。

CoreDataを使ったRubyCocoaの15パズルアプリで、使ってるうちに特異メソッドにアクセスできなくなって、アプリが落ちてしまうという現象が起きて困っているとのこと。rubyオブジェクトとcocoaオブジェクトをひも付けしているキャッシュシステムがあやしいんじゃないのという感じ。

再現させるアプリが提供されたので調査はわりとすんなり。問題はキャッシュシステムじゃなくて、pure Cocoaのオブジェクトに特異メソッドを定義していること。これらのオブジェクトがrubyから参照されていない(特異メソッド定義時のみローカル変数として参照)ために、GCruby側のオブジェクトが回収されてしまい、再度利用するときには特異メソッドのない新規のラッパーオブジェクトが生成されて利用される。その結果、定義したはずの特異メソッドが利用できなくなってしまう、という現象。

考えてみれば理解できるけれど、コード書くときには気にしないよな、そんなこと。

解決方法としてはruby側から長期的な参照を確保するしかなくて、例として

  • rubyインスタンス変数にpure Cocoaオブジェクトをつっこむ
  • クラスをruby側で定義したNSManagedObjectのサブクラスにする
  • GC.disable

を挙げておいた。もちろん最後のは冗談ね。ていうか、特異メソッド使わないのがいちばんだと思うよ、このケースでは。

MacRubyだと世界はひとつ(Ruby界===Cocoa界)なので、この問題は起きないらしい。