5

こんにちは、Objective Cは初めてで、誰かがこれを手伝ってくれるのではないかと考えていました。それぞれ3つの入力値を必要とするいくつかの異なるメソッドがあり、通常は

[self methodA:1 height:10 speed:3]

しかし、plistの文字列から読み取りたいメソッド名なので、たとえば、文字列がmethodBの場合、次のようになります。

[self methodB:1 height:10 speed:3] 

「methodC」の場合

[self methodC:1 height:10 speed:3]

等々。

これをどのように行うかについてのアイデアは、NSSelectorFromStringを使用して文字列をセレクターとして定義してみました

NSString *string = [plistA objectForKey:@"method"];
SEL select = NSSelectorFromString(string);
[self performSelector:select:c height:b speed:a]; 

しかし、これはうまくいきませんでした。助けていただければ幸いです。以下の解決策を試しましたが、ここで動作することができませんでしたが、私が試したものです。

要約すると、次のような方法があります。

 spawnEnemyA:2 withHeight:3 withSpeed:4  
 spawnEnemyB:3 withHeight:2 withSpeed:5 

そして、これらのメソッドに渡したい値と、plistファイルからメソッドタイプを読み取りたいと思います。私のコードは次のとおりです。 //////////////////

//これらは、メソッドで使用するplistから読み取った値です

    int a = [[enemySettings objectForKey:@"speed"] intValue];
    int b = [[enemySettings objectForKey:@"position"] intValue];
    int c = [[enemySettings objectForKey:@"delay"] intValue];

   // I Also read the method name from the plist and combine it into a single string  
    NSString *method = [enemySettings objectForKey:@"enemytype"];
    NSString *label1 = @"spawn";
    NSString *label2 = @":withHeight:withSpeed:";
    NSString *combined = [NSString stringWithFormat:@"%@%@%@",label1, method,label2];


    //Check that the string is correct get spawnEnemyA:withHeight:withSpeed:
    CCLOG(@"%@",combined);


//This is the Invocation part 
    NSInvocation * invocation = [ NSInvocation new ];

    [ invocation setSelector: NSSelectorFromString(combined)];
    [ invocation setArgument: &c atIndex: 2 ];
    [ invocation setArgument: &b atIndex: 3 ];
    [ invocation setArgument: &a atIndex: 4 ];

    [ invocation invokeWithTarget:self ];

    [invocation release ];

////////////////////////////////////////////////// //////////////////

コードはエラーなしでコンパイルされますが、メソッドは呼び出されません。何か案は?乾杯

4

4 に答える 4

11

performSelector3 つ (またはそれ以上) の引数を持つメソッドには使用できません。
参考までに、使用方法は次のとおりです。

SEL m1;
SEL m2;
SEL m3;

m1 = NSSelectorFromString( @"someMethodWithoutArg" );
m2 = NSSelectorFromString( @"someMethodWithAnArg:" );
m1 = NSSelectorFromString( @"someMethodWithAnArg:andAnotherOne:" );

[ someObject performSelector: m1 ];
[ someObject performSelector: m2 withObject: anArg ];
[ someObject performSelector: m2 withObject: anArg withObject: anOtherArg ];

2 つ以上の引数を持つメソッドの場合、 NSInvocationクラスを使用する必要があります
使用方法については、ドキュメントを参照してください。

基本的:

NSInvocation * invocation = [ NSInvocation new ];

[ invocation setSelector: NSStringFromSelector( @"methodWithArg1:arg2:arg3:" ) ];

// Argument 1 is at index 2, as there is self and _cmd before
[ invocation setArgument: &arg1 atIndex: 2 ];
[ invocation setArgument: &arg2 atIndex: 3 ];
[ invocation setArgument: &arg3 atIndex: 4 ];

[ invocation invokeWithTarget: targetObject ];

// If you need to get the return value
[ invocation getReturnValue: &someVar ];

[ invocation release ];
于 2012-06-20T18:21:20.680 に答える
4

一般に、この種のダイナミズムはしばしばアンチパターンを示します。このようにデータと実装を共謀することは、通常、ベスト プラクティスではありません。

ただし、必要な場合もあります。このパスをたどる場合、さまざまなメソッド宣言が次のようになる可能性が高いとします。

- (void)methodAWidth:(NSUInteger)w height:(NSUInteger)h speed:(NSUInteger)s;
- (void)methodBWidth:(NSUInteger)w height:(NSUInteger)h speed:(NSUInteger)s;
- (void)methodCWidth:(NSUInteger)w height:(NSUInteger)h speed:(NSUInteger)s;

あなたはおそらく次のようなものが欲しいでしょう:

NSString *selName = [NSString stringWithFormat:@"method%@Width:height:speed:", ... one of @"A", @"B", or @"C" ....];
SEL selector = NSelectorFromString(selName);

それで:

if (![target respondsToSelector:selector])
    return; // no can do

void (*castMsgSend)(id, SEL, NSUInteger, NSUInteger, NSUInteger) = (void*)objc_msgSend;
castMsgSend(target, selector, 1, 10, 3);

すべてのメソッド呼び出しは、への呼び出しにコンパイルされobjc_msgSend()ます。上記を行うことで、通常の Objective-C メッセージング メカニズムを通過する、完全にタイプ セーフ/タイプ チェックされた呼び出しサイトを作成していますが、セレクターはその場で動的に定義されます。\

(および複数引数のバリアント) は便利ですが、非オブジェクト型をperformSelector:扱うことはできません。


また、MacMade がコメントで指摘したように、浮動小数点と構造体の戻り値に注意してください。[foo bar]これらは、コンパイラが通常のケースで自動的に処理する objc_msgSend() のさまざまなバリアントを使用します。

于 2012-06-20T18:32:30.110 に答える
1

直接使用できますobjc_msgsend

NSString *methodName = [plistA objectForKey:@"method"];
objc_msgSend(self, methodName, c, b, a);

セレクターにはすべてのピースを含める必要があることに注意してください。@"method:height:speed:"

于 2012-06-20T18:19:43.757 に答える
-1

次の行を次のように置き換える必要があります。

[self performSelector:select:c height:b speed:a];

次のように記述します。

[self performSelector:select withObject:[NSArray arrayWithObjects:c,b,a,nil]];
于 2012-06-20T18:28:39.597 に答える