ページ

2009年7月15日水曜日

NSInvocation を使う

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク

前回 - [AppController hotkeyShouldChange:] の戻り値は Number*型だった。

- (Number*)hotkeyShouldChange:(Hotkey*)hotkey


これは呼び出しに -(id)performSelector:withObject: を使っていたため。

このままでも良いのだが何となく気になる。使い勝手の点から考えても戻り値は BOOL型にしたい。
- (BOOL)hotkeyShouldChange:(Hotkey*)hotkey



そこで、メソッドを上記のように変更し、呼び出し側も perfomSelect:withObject: をやめて直接メッセージを送ってみる。
[self.target hotkeyShouldChange:_hotkey]


これでうまくいった。
が、コンパイラが Warningを出す。


これは当たり前でヘッダファイルでの定義が無いため。

通常ならデリゲートはプロトコルやカテゴリ(非形式プロトコル)を使い @interface定義しておくのだが、メソッドもたった一つなので大げさな気もする。

そこで勉強も兼ねて NSInvocation を使ってみよう。

参考情報:
NSInvocation Class Reference

Distributed Objects Programming Topics - Using NSInvocation

NSMethodSignature Class Reference

上記情報を参考に呼び出し側を書き換えてみた。
HotkeyTextView.m
旧コード
if ([self.target hotkeyShouldChange:_hotkey]) {
  :


HotkeyTextView.m
新コード
SEL selector = @selector(hotkeyShouldChange:);
NSMethodSignature* signature = [self methodSignatureForSelector:selector];
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
BOOL result;
[invocation setSelector:selector];
[invocation setTarget:self.target];
[invocation setArgument:&_hotkey atIndex:2];
[invocation invoke];
[invocation getReturnValue:&result];

if (result) {
  :


実行する。あえなく玉砕。。デバッガが起動した。
プログラムをデバッガに読み込み中...
GNU gdb 6.3.50-20050815 (Apple version gdb-962) (Sat Jul 26 08:17:57 UTC 2008)
Copyright 2004 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB. Type "show warranty" for details.
This GDB was configured as "powerpc-apple-darwin".プログラムは読み込まれました。
sharedlibrary apply-load-rules all
Attaching to program: `/Users/hashi/Documents/Private/study/Hotkey/build/Debug/Hotkey.app/Contents/MacOS/Hotkey', process 6435.
kill

The Debugger デバッガはプロセスに接続しています(gdb)


コード書いていて見当はついていたのだがシグネチャ(NSMethodSignature)の作成がまずいのだろう。上記のコードだけだと NSInvocationからすると引数の型も戻り値も判断できない。他のサイトの情報も見るとサンプルコードの多くは呼び出し側にわざわざメソッドを用意しているか、あらかじめターゲットのクラスを決め打ちしてそこから情報を得ている。どうも実在するメソッドでないとだめのようだ。

試しに呼び出すメソッドをこのクラスに追加してみる。
HotkeyTextView.m
- (BOOL)hotkeyShouldChange:(Hotkey*)hotkey
{
// dummy method
return NO;
}


すると今度はうまく動作した。

恐らく - [NSObject methodSignatureForSelector:] が、送られる先のオブジェクト(今回は self、すなわち HotkeyTextView)から実行時に引数と戻り値の型情報を得ているのだと思われる。

- - - -
これで動く様になったのだがダミーのメソッドが必要になってしまう。うーむ。