きりかノート 3冊め

おあそびプログラミング

Objective-C での _cmd の使い道

ダイナミック Objective-C28回「ランタイムAPIでさらに動的に(2)」29回「〜(3)」)では、C の関数を Objective-C のメソッドとして追加/置き換えすることについて言及されてる。ここでの C の関数の引数が、型エンコード(連載の20回「メソッドとは何か(3)」参照)の2番め以降で表されているわけだ。で、必ずレシーバ(self)とセレクタ(_cmd)を受け取る。なんだけど、セレクタはなくてもいいんじゃないの?と思わなくもない。

たとえば ruby では、メソッドを C で定義するときはレシーバに相当する VALUE 型の引数をとるけれども、メソッド名は受け取らない。([ruby-dev:28471] あたりを見てると、インタプリタは呼び出されたメソッド名を知っているので、取得することはできると思う。未検証)

同じ関数で、セレクタ/メソッド名によって振る舞いを変更したいってときには、まあ利用できる。だけど、そんなケースはあまり思い浮かばない。そこで RubyCocoaRubyCocoa では、このセレクタの値をばっちり使っている。具体的に挙げると、handle_ruby_method()(OverrideMixin.m)での、Objective-C から ruby で定義されたメソッドを呼び出しているところ。

RubyCocoa では、ns_override や addRubyMethod:withType: などにより、ruby から Objective-C のメソッドを追加することができる(ns_override も内部的には追加)。ここで Objective-C のメソッドの実装(IMP)としては、いつも同じ関数(*1)が class_addMethods() される。で、実際にそのメソッドが呼び出されたときに、そのセレクタに相当する ruby のメソッドを探して呼び出している。

というわけで _cmd の活躍する現場もあるよって話。おしまい。

(*1) 正確には2つの関数のどちらか。返り値の型が id より大きいサイズのときと、そうでないとき。/usr/include/objc/objc-runtime.h の objc_msgSend_stret() あたりを参照のこと。