3

あなたの助けが必要です。NSInvocation 'getReturnValue:' メソッドに問題があります。UIButton をプログラムで作成したいのですが、さらに、NSInvocation を使用し、NSArray を介して値を渡すことで動的に作成したいと考えています (そのため、UIButtonTypeRoundedRect をラップしました)。

リスト。

NSLog(@"Button 4 pushed\n");//this code executed when button pushed
Class cls = NSClassFromString(@"UIButton");//if exists {define class},else cls=nil
SEL msel = @selector(buttonWithType:);
//id pushButton5 = [cls performSelector:msel withObject:UIButtonTypeRoundedRect];//this code works correctly,but I want to do this by NSInvocation
//---------------------------
NSMethodSignature *msignatureTMP;
NSInvocation *anInvocationTMP;

msignatureTMP = [cls methodSignatureForSelector:msel];
anInvocationTMP = [NSInvocation invocationWithMethodSignature:msignatureTMP];
[anInvocationTMP setTarget:cls];
[anInvocationTMP setSelector:msel];

UIButtonType uibt_ = UIButtonTypeRoundedRect;
NSNumber *uibt = [NSNumber numberWithUnsignedInt:uibt_];
NSArray *paramsTMP;
paramsTMP= [NSArray arrayWithObjects:uibt,nil];

id currentValTMP = [paramsTMP objectAtIndex:0];//getParam from NSArray
NSInteger i=2;
void* bufferTMP;

//if kind of NSValue unwrapp it.
if ([currentValTMP isKindOfClass:[NSValue class]]) {
    NSUInteger bufferSize = 0;
    NSGetSizeAndAlignment([currentValTMP objCType], &bufferSize, NULL);
    bufferTMP = malloc(bufferSize);
    [currentValTMP getValue:bufferTMP];//copy currentVal to bufer
    [anInvocationTMP setArgument:bufferTMP atIndex:i];// The +2 represents the (self) and (cmd) offsets
}else {
    [anInvocationTMP setArgument:&currentValTMP atIndex:i];//Again,+2 represents (self) and (cmd) offsets
}
void* result = malloc([[cls methodSignatureForSelector:msel] methodReturnLength]);
[anInvocationTMP invoke];
[anInvocationTMP getReturnValue:result];

NSLog(@"sizeof(UIButton)=%i,sizeof(result)=%i,methodreturnlength = %i,sizeof(*result)=%i",class_getInstanceSize(NSClassFromString(@"UIButton")),sizeof(result),[[cls methodSignatureForSelector:msel] methodReturnLength],sizeof(*result));

id pushButton5;
pushButton5=result;
//---------------------------

NSLog 出力: sizeof(UIButton)=140、sizeof(result)=4、methodreturnlength = 4、sizeof(*result)=1

問題は、NSInvocation からの値がサイズ 4 バイトのポインターであることです。サイズが 140 バイトの UIButton オブジェクトを指す必要があります。しかし、実際には 1 バイトのデータを指します。'buttonWithType:' で初期化する必要がある UIButton オブジェクトはどうなりますか?

いくつかの回答を得た後に追加されました:

UIButton明確にするために:私はオブジェクトを取得したいのですが、このコードid pushButton5 = (id) result;の後、操作しようとするpushButton5EXC_BAD_ACCESS. 誰かが私を助けることができますか?

これが原因で起こり得るのでしょうか?

Class cls = NSClassFromString(@"UIButton");
...
[anInvocationTMP setTarget:cls];

正しいですね。

4

5 に答える 5

18

ARC を使用している場合は、これを置き換えます。

void* result = malloc([[cls methodSignatureForSelector:msel] methodReturnLength]);
[anInvocationTMP invoke];
[anInvocationTMP getReturnValue:result];

これとともに:

CFTypeRef result;
[anInvocationTMP invoke];
[anInvocationTMP getReturnValue:&result];
if (result)
    CFRetain(result);
UIButton *pushButton5 = (__bridge_transfer UIButton *)result;

その理由は、呼び出しの戻りオブジェクトが保持されないためです。そのため、最初にそれを保持してから ARC に所有権を譲渡するように指示しない限り、すぐにオブジェクト参照に割り当てても、消えてしまいます。

于 2012-07-19T21:02:05.357 に答える
1

resultタイプがvoid*あり、sizeof(*result)式が measuingsizeof(void)であり、コンパイラで明らかに 1 が生成されます。

Objective-C オブジェクトの型を確認するには、次のisKindOfClass:メソッドを使用します。

id resObj = (id)result;
if ([resObj isKindOfClass:[UIButton class]])
    NSLog(@"mazel tov, it's a button");

最初にそれが本当に目的の c オブジェクトであることを確認してください。

于 2011-08-16T12:49:45.193 に答える
0

問題じゃない。

まず、getReturnValue:呼び出しの後に来る必要があります。それで、

[anInvocationTMP getReturnValue:result];
[anInvocationTMP invoke];

する必要があります

[anInvocationTMP invoke];
[anInvocationTMP getReturnValue:result];

次に、それ自体のサイズを忘れる必要がありUIButtonます。buttonWithType返されるのはUIButton*、ではなくですUIButton。Objective-Cでは、オブジェクト自体を直接処理しないでください。常にオブジェクトへのポインタを操作する必要があります。

最後に、(Objective-)Cのsizeof演算子は純粋にコンパイル時の操作です。したがって、実行時にsizeof(*result)何を指しているのかまったくわかりません。しかし、それは問題ではありません...私がすでにあなたに言ったように、あなたresultはのサイズを気にするべきではありません。UIButton

于 2011-08-16T12:31:18.653 に答える
0

私が本当に必要としていた答えは... どこだと思いますか? はい、ドキュメントにあります。

  • NSMethodSignatureメソッドを使用してmethodReturnLength、 buffer に必要なサイズを決定します。

    NSUInteger length = [[myInvocation methodSignature] methodReturnLength];
    buffer = (void *)malloc(length);
    [invocation getReturnValue:buffer];
    
  • 戻り値がオブジェクトの場合、オブジェクトを配置する変数 (またはメモリ) へのポインターを渡します。

    id anObject;
    NSArray *anArray;
    [invocation1 getReturnValue:&anObject];
    [invocation2 getReturnValue:&anArray];
    

それで問題は解決しました。返信ありがとうございます。

于 2011-08-17T07:58:48.540 に答える
0

戻り値は UIButton ではなく UIButton* です。したがって、コードではすべてがうまく見えます。

于 2011-08-16T12:25:44.493 に答える