5

嗨,我是目标 C 的新手,想知道是否有人可以帮助我解决这个问题。我有几种不同的方法,每种方法都需要 3 个输入值,通常使用

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

但是我想从plist中的字符串中读取方法名称,例如,如果字符串是methodB,我会得到

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

对于“方法C”

[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

您不能使用performSelector具有 3 个(或更多)参数的方法。
但为了您的信息,这里是如何使用它:

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 回答