嗨,我对目标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 ];
/////////////////////////////////////////////// /////////////////////
代码编译没有任何错误,但不调用方法。有任何想法吗?干杯
答案 0 :(得分: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 ];
答案 1 :(得分: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:
(以及多arg变体)很方便,但它们无法处理非对象类型。
而且,正如MacMade在评论中指出的那样,要注意浮点数和结构回报。它们使用不同的objc_msgSend()变体,编译器会自动处理正常的[foo bar]
情况。
答案 2 :(得分:1)
您可以直接使用objc_msgsend
:
NSString *methodName = [plistA objectForKey:@"method"];
objc_msgSend(self, methodName, c, b, a);
请注意,选择器必须包含所有部分,例如@"method:height:speed:"
答案 3 :(得分:-1)
您应该将以下行替换为:
[self performSelector:select:c height:b speed:a];
并写下以下内容:
[self performSelector:select withObject:[NSArray arrayWithObjects:c,b,a,nil]];