カテゴリ
先にGNUランタイムのままカテゴリやります。
カテゴリは既存のクラスに後からメソッドを追加する機能です。
Objectクラスにputを足してみます。
with Interfaces.ObjC; use Interfaces.ObjC; procedure gnu_step4_cat is function Object_put (self : id; op : SEL) return id; pragma Convention (C, Object_put); My_Category_Name : constant String := "My_Category" & ASCII.NUL; Target_Class_Name : constant String := "Object" & ASCII.NUL; put_Name : constant String := "put" & ASCII.NUL; Method_Type : constant String := "@8@0:4\0" & ASCII.NUL; My_Category_Methods : aliased objc_method_list := ( method_next => null, method_count => 1, method_list => (1 => ( Address_To_SEL (put_Name'Address), Method_Type (1)'Unrestricted_Access, Object_put'Unrestricted_Access))); My_Category : aliased objc_category := ( category_name => My_Category_Name (1)'Unrestricted_Access, class_name => Target_Class_Name (1)'Unrestricted_Access, instance_methods => My_Category_Methods'Unchecked_Access, class_methods => null, protocols => null); My_Symbol_Table : aliased constant Symtab_With_defs := ( cls_def_cnt => 0, cat_def_cnt => 1, symtab => (0, null, 0, 1), cls_defs => (1 .. 0 => <>), cat_defs => (1 => My_Category'Unchecked_Access), end_defs => null); My_Module : aliased constant Module := ( symtab => My_Symbol_Table.symtab'Unchecked_Access, others => <>); function Object_put (self : id; op : SEL) return id is procedure puts (s : not null access constant Character); pragma Import (C, puts); begin puts (objc_msgSend (self, selector ("name"))); return self; end Object_put; begin objc_exec_class (My_Module'Access); declare Object : id := objc_msgSend (objc_msgSend ( Class_To_Object (objc_get_class ("Object" & ASCII.NUL)), selector ("alloc")), selector ("init")); begin objc_msgSend (Object, selector ("put")); objc_msgSend (Object, selector ("free")); end; end gnu_step4_cat;
堪え切れなくなってラッパー書きました。selectorとobjc_msgSendがそうです。objc_msgSendはAppleランタイムの同名の関数と同じ仕様。
実行結果。
ObjectあとposeAs:というメッセージを使えば、既存クラスを丸ごと差し替えることもできるみたいです。誰かNSTextViewの派生クラスでスクロールを画面の半分ではなく1行単位にしたやつ作って無いでしょうか。poseAs:して全部置き換えたいです。 プロトコルはプロセス境界越えて通信しない限り関係ないので割愛したいと思います。 あとobjc_msgSendvの使い方がわからん。float型の受け渡し周りでポータビリティに難があるような話もありますので、こんなもん使うぐらいならインラインアセンブラでスタック弄った方がいいんじゃないかと思えてしまうのが。