.-- --

スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。
スポンサー広告 comment(-) trackback(-)
.12 2010

NSInvocationで動的結合を体感

Tasakiです。

今週、SDK3.2もbeta4がリリースされましたね。
実機の方も4月発売ということで、国内ではXperia vs iPadな状況になってきました。
これで3G版のキャリアがdocomoなら、まさにそういう構図になりそうですが…

今回のテーマは、Objective-Cの特徴でもある動的結合に関するものです。
Objective-CはCに動的結合の機能を付加したものと言っても過言ではないですし(ですよね?)、この機能は抑えておいた方がよいでしょう。

Objective-Cのメソッドは通常、[ obj call ]といった様に直接呼び出すのが。
この他に、以下のようにセレクタを渡して、間接的にメソッドを呼び出す方法もあります。
[ obj performSelector: @selector( call ) withObject: nil ];
2番目の引数には、先頭のパラメータを渡します。
上の例では、引数を取りませんので、nilにしておきます。

では、引数が2つある場合はというと、以下のようになります。
[ obj performSelector: @selector( call:withA:withB: ) withObject: arg1 withObject: arg2 ];

しかし後ろにパラメータが増えていくこの方法では、どう考えても対応に限界があります。
というわけで、3つ以上の引数を取る場合は、別の方法をし使用しなければなりません。
また、この方法では、引数がObjective-Cのオブジェクトである必要がありそうです。

そこで登場するのが、NSInvocationクラスです。
このクラスを使用するとより複雑なメソッドでも呼び出しが可能になります。

以下に処理の流れを示します。
1.メソッドシグネチャを取得
2.上記オブジェクトからインボケーションオブジェクトを作成
3.ターゲットオブジェクトを設定
4.ターゲットセレクタを設定
5.引数を設定
6.メソッドの呼び出し
7.返り値の取得

例として、NSStringの以下のメソッドを呼び出す場合は、
- ( NSString* ) stringByReplacingOccurrencesOfString:( NSString* ) target withString:( NSString* ) replacement options:( NSStringCompareOptions ) options range:( NSRange ) searchRange

次のようになります。
NSString* string = ...;
NSString* target = ...;
NSString* replace = ...;
NSStringCompareOptions options = ...;
NSRange range = ...;
NSString* retVal = nil;

SEL selector = @selector( stringByReplacingOccurrencesOfString:withString:options:range: );
// メソッドシグネチャを取得
NSMethodSignature* signature = [ string methodSignatureForSelector: selector ];
// インボケーションを作成
NSInvocation* invocation = [ NSInvocation invocationWithMethodSignature: signature ];
// オブジェクトを設定
[ invocation setTarget: string ];
// セレクタを設定
[ invocation setSelector: selector ];
// 引数を設定
[ invocation setArgument:( void * ) &target atIndex: 2 ];
[ invocation setArgument:( void * ) &replace atIndex: 3 ];
[ invocation setArgument:( void * ) &options atIndex: 4 ];
[ invocation setArgument:( void * ) &range atIndex: 5 ];
// メソッドの呼び出し
[ invocation invoke ];
// 返り値の取得
[ invocation getReturnValue:( void * ) &retVal ];

注意点としましては、
・引数や返り値の受け渡しには、変数のポインタを使用する
・引数設定の際のインデックスには、引数の順番 + 1 を使用する
等が挙げられます。

たった1つのメソッドを呼ぶだけでこのような労力が必要となってしまいますが、クラスやメソッドが未定義であっても、コンパイルエラーを回避することが可能になり、場合によっては必要となるテクニックであることは確かなので、覚えておいて損はないでしょう。

関連記事
スポンサーサイト

Comment

anony
forwardInvocationで受信したメッセージを返すクラスオブジェクトを用意しておくともっと便利になりますよ。こんな感じです。

id message = [ MessageCapture arg1:0 arg2:"a" arg3:100 ];
id target = [[ExampleClass alloc] init];
[message invorkeWithTarget:target];

forwardInvocationで勝手にメッセージが組み上がるので、長々とメッセージを組み立てる手間が掛かりません。
2013.02.07 22:45
Tasaki
> anony さん
なるほど
適当なオブジェクトにメッセージを投げておけば、NSObject自身がインボケーションオブジェクトを作ってくれるので、それを使ってしまうということですね。
すごく勉強になりました。
ありがとうございました!
2013.02.08 09:38

Post comment

  • comment
  • secret
  • 管理者にだけ表示を許可する

Trackback

trackbackURL:http://appteam.blog114.fc2.com/tb.php/97-3ee768a1

ブログ内検索

関連リンク

製品情報

最新記事

カテゴリ

プロフィール

neoxneo



NEXT-SYSTEM iOS Developers Blog


  • UTO:
    カナダ版iPhone4Sは、マナーモードでシャッター音がならない…


  • Ehara:
    ...


  • Hayate:
    ...


  • Tasaki:
    Developer登録完了...したのはいいけど


  • Ueda:
    ...



リンク

上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。