8

だから私は Java の世界から来たので、メモリ管理の問題を幸いなことに無知です。ほとんどの場合、ARC は私のお尻を救ってくれましたが、ここで私を困惑させたことがあります。基本的に、私はいくつかのものに NSInvocations を使用していますが、次のコード変更を行う前に、いくつかの厄介なメモリの問題に遭遇しました。これらの変更を行ってから、メモリ クラッシュはなくなりましたが、私は通常、理解できないコードを非常に恐れています。私はこれを正しく行っていますか?

前: あらゆる種類のメモリの問題:

NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[[target class] instanceMethodSignatureForSelector:selector]];
[invocation setSelector:selector];
[invocation setTarget:target];
[invocation setArgument:&data atIndex:2];
[invocation setArgument:&arg atIndex:3];
[invocation invoke];

NSString *returnValue;
[invocation getReturnValue:&returnValue];

後:メモリの問題はありませんが、これが正しいかどうかはわかりません:

NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[[target class] instanceMethodSignatureForSelector:selector]];
[invocation setSelector:selector];
[invocation setTarget:target];
[invocation setArgument:&data atIndex:2];
[invocation setArgument:&arg atIndex:3];
[invocation invoke];

CFTypeRef result;
[invocation getReturnValue:&result];

if (result)
    CFRetain(result);

NSString *returnValue = (__bridge_transfer NSString *)result;

編集:

以下の回答に基づいて追加したかったので、objc_msgSendを使用しました。

NSString * returnValue = objc_msgSend(target, selector, data, arg);

また、すべてのメモリの問題が解決され、見た目がはるかにシンプルになります。これに問題がある場合はコメントしてください。

4

2 に答える 2

5

私はあなたの質問に次のように答えます:使用しないでくださいNSInvocation可能であればそれを避けるためのフレンドリーなアドバイスです。

Objective-C でコールバックを行うための便利な方法はたくさんあります。

  • ブロック: コンテキストで定義され、任意の引数の数と型を選択します。メモリの問題も考えられます。それらの使用方法に関する多くのリソースがあります。
  • performSelector : 最大 2 つのオブジェクト引数。以下を使用して呼び出されます。

    [target performSelector:selector withObject:data withObject:args];
    

さらに、4 つの引数でセレクターを呼び出す必要がある場合は、まだ を使用せず、直接NSIvocation呼び出します。objc_msgSend

id returnValue = objc_msgSend(target, selector, data, /* argument1, argument2, ... */);

単純。

編集:戻り値にobjc_msgSend注意する必要があります。メソッドがオブジェクトを返す場合は、上記を使用します。プリミティブ型を返す場合は、objc_msgSendメソッドをキャストして、コンパイラが何が起こっているかを知る必要があります (このリンクを参照してください)。1 つの引数を取り、BOOL を返すメソッドの例を次に示します。

// Cast the objc_msgSend function to a function named BOOLMsgSend which takes one argument and has a return type of BOOL.
BOOL (*BOOLMsgSend)(id, SEL, id) = (typeof(BOOLMsgSend)) objc_msgSend;
BOOL ret = BOOLMsgSend(target, selector, arg1);

メソッドが構造体を返す場合、事態はもう少し複雑になります。使用する必要がある場合があります (常にではありません) --詳細objc_msgSend_stretについては、こちらを参照してください

編集: - この行をコードに追加する必要があります。そうしないと、Xcode が文句を言います:

#import <objc/message.h>

また

@import ObjectiveC.message;
于 2013-07-07T07:16:45.533 に答える