2

正しい引数値をNSInvocation使用して、現在のメソッドの を動的に作成したいと考えています。通常、次のようにします。

- (void)messageWithArg:(NSString *)arg arg2:(NSString *)arg2
{
    NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[self methodSignatureForSelector:_cmd]];
    [invocation setTarget:self];

    /*
     * How do we set the argument values here dynamically?
     */
}

引数の値を明示的に設定するのは簡単で、次のようなことができます。

[invocation setArgument:&arg atIndex:2];
[invocation setArgument:&arg2 atIndex:3];

次のようなループでこれを実行できるようにしたい:

for(int i = 0; i < [[self methodSignatureForSelector:_cmd] numberOfArguments]; i++) {
    [invocation setArgument:?!?! atIndex:i + 2];
}

難しい部分は、特定のインデックスの引数値を動的に取得することです。

同様の質問がここで尋ねられました。回答者は、クラスの複雑さを理由に解決策を認識していないと述べています。複雑さについては同意しません.コンパイラは使用されている呼び出し規約を認識しているため、スタックフレームが設定された後にスタックがどのように見えるかは、基礎となるコードで既に正確にわかっています. たとえば、x86 ではstdcall、引数値が からの固定オフセットであることがわかっているため、引数値に簡単にアクセスできますebp

  • 古い0 ebp( %ebp)
  • リターンアドレス4(%ebp)
  • 8(%ebp)最初の引数

どうすれば欲しいものを達成できますか、または引数値のインデックスベースのフェッチをサポートするメカニズムが言語に実際に存在しませんか? C標準にはそのような機能が存在しないため、現時点ではこれを真と見なすことができます。ただし、この理由の確認および/または説明を求めたいと思います。

4

1 に答える 1

0

これは機能しますが、私が期待したものではありません。va_start used in function with fixed argumentsエラーにより、通常の方法で va_start を使用できなくなります。あなたがこれを達成しようとしていることに依存します。

@interface Test : NSObject

- (void)method:(id)arg1 :(id)arg2;

@end

@implementation Test

+ (void)load {
    class_addMethod([Test class], @selector(method::), (IMP)method_imp, "v@:@@");
}

void method_imp(id self, SEL _cmd, ...) {
    va_list ap;
    va_start(ap, _cmd);
    SEL sel = NSSelectorFromString([@"_" stringByAppendingString:NSStringFromSelector(_cmd)]);
    NSMethodSignature *signature = [self methodSignatureForSelector:sel];
    NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
    int argc = [signature numberOfArguments];
    char *ptr = (char *)ap;
    for (int i = 2; i < argc; i++) {
        const char *type = [signature getArgumentTypeAtIndex:i];
        [invocation setArgument:ptr atIndex:i];
        NSUInteger size;
        NSGetSizeAndAlignment(type, &size, NULL);
        ptr += size;
    }
    va_end(ap);
    [invocation setSelector:sel];
    [invocation invokeWithTarget:self];
}

- (void)_method:(id)arg1 :(id)arg2 {
    NSLog(@"%@, %@, %@", NSStringFromSelector(_cmd), arg1, arg2);
}

@end

呼び出しmethod::は終了し_method::、何もハードコードされていません

Test *test = [[Test alloc] init];
[test method:@"arg1" :@"arg2"];  // log: _method::, arg1, arg2
于 2013-02-01T12:28:54.907 に答える