Seasons.NET

ちょっとした技術ブログです

CCSendMessageを使えばBlocksっぽい処理が実現出来るよ!!

最近、CCSendMessageという素晴らしく
便利なクラスを発見したので紹介します。
元記事


そもそもなぜこれがここに来て登場したかというと、
CCCallFuncを使って、

  • アクションの最後に何かしたいとか、
  • 複数の引数をセレクタに渡して何かしたいとか、

意外と融通が利かないことが多いです。


というか何より、selfとセレクタ渡すのがめんどくさい!!
これは私も思ってました。


CCSendMessageはそれを解決してくれます。


CCSendMessageの使い方は、非常に簡単です。
例えば、CCSpriteのオブジェクトをアクションの後に消去したいときを考えて見ましょう。
CCCallFuncならこのように記述するでしょう。

@interface CCSprite2 : CCSprite {
@end


@implementation CCSprite2
- (void) removeSprite {
    
    [self removeFromParentAndCleanup:YES];
}
@end
// s  = CCSpriteから派生したスプライトクラス
CCMoveBy *move = [CCMoveBy actionWithDuration:1.0 position:ccp(0,100)];
CCCallFunc *remove = [CCCallFunc actionWithTarget:s selector:@selector(removeSprite)];
        
CCSequence *seq = [CCSequence actions:move,remove, nil];
[s runAction:seq];


CCSendMessageではこう書きます。

// s = CCSpriteでOK

CCSendMessages *remove = [CCSendMessages actionWithTarget:s];
CCMoveBy *move = [CCMoveBy actionWithDuration:1.0 position:ccp(0,100)];

[[remove addMessage] removeFromParentAndCleanup:YES]; 
CCSequence *seq = [CCSequence actions:move,remove, nil];
[s runAction:seq];


CCSendMessagesに渡したオブジェクトを内部で保持しており、
addMessageメソッドで呼び出したいメソッドを登録していきます。

[[remove addMessage] removeFromParentAndCleanup:YES]; 

addMessageで追加したメッセージは配列で保持しているので、
登録された分のメッセージが1度に呼び出されます。
また、ワンショットなので呼び出した後、もう1度呼び出すことはありません。


そもそもどうして、CCNodeの持つremoveFromParentAndCleanupを
いきなり記述できるかというと、CCSendMessagesでは内部で
methodSignatureForSelectorとforwardInvocationを実装しているので、
登録したオブジェクトにそのメソッドが登録されているかどうか調べてセレクターを
取得することが出来ます。


これにより以下のような記述が可能になるわけです。
※CCCallFuncではこれを実現するためにtargetとselectorを渡すことで実現しています。

[[remove addMessage] removeFromParentAndCleanup:YES]; 


複数の引数を渡すメソッドの登録も簡単です。
次の例は引数を1つだけ渡すメソッドですが、
CCSendMessagesを生成する際に渡したオブジェクトに
setNumberというメソッドが実装されているためこのように記述することができます。

- (void) setNumber : (NSNumber *)number {
    
    NSLog(@"number retain:%d" , [number retainCount]);
}
[[remove addMessage] setNumber:[NSNumber numberWithInt:10]];

サンプルコードも用意しました。
https://gist.github.com/1007736

cocos2dテンプレートから新規プロジェクトを作り、
HelloWorld.mにコピペすれば使えるはずです。


当然ですが、ここからCCSendMessagesのソースを
手に入れてプロジェクトに追加してください。



iOS4以降では、Blocksを使った実装がスマートですが、
iOS3もサポートしているアプリケーションにはこのCCSendMessagesはとても便利だと思います。