140

正確にはどのように機能しNSInvocationますか?良い紹介はありますか?

次のコード ( Cocoa Programming for Mac OS X, 3rd Editionから) がどのように機能するかを理解するのに特に問題がありますが、チュートリアルのサンプルとは別に概念を適用することもできます。コード:

- (void)insertObject:(Person *)p inEmployeesAtIndex:(int)index
{
    NSLog(@"adding %@ to %@", p, employees);
    // Add inverse of this operation to undo stack
    NSUndoManager *undo = [self undoManager];
    [[undo prepareWithInvocationTarget:self] removeObjectFromEmployeesAtIndex:index];
    if (![undo isUndoing])
        [undo setActionName:@"Insert Person"];

    // Finally, add person to the array
    [employees insertObject:p atIndex:index];
}

- (void)removeObjectFromEmployeesAtIndex:(int)index
{
    Person *p = [employees objectAtIndex:index];
    NSLog(@"removing %@ from %@", p, employees);
    // Add inverse of this operation to undo stack
    NSUndoManager *undo = [self undoManager];
    [[undo prepareWithInvocationTarget:self] insertObject:p
                                       inEmployeesAtIndex:index];
    if (![undo isUndoing])
        [undo setActionName:@"Delete Person"];

    // Finally, remove person from array
    [employees removeObjectAtIndex:index];
}

私はそれがやろうとしていることを理解しています。(ところで、employeesカスタムNSArrayクラスPersonです。)

.NET の専門家として、なじみのない Obj-C および Cocoa の概念を、ほぼ類似した .NET の概念に関連付けようとします。これは .NET のデリゲートの概念に似ていますが、型付けされていませんか?

これは本から 100% 明らかになっているわけではないので、単純な (っぽい) 例の下にある基本的な概念を理解することを目標に、実際の Cocoa/Obj-C の専門家から補足的なものを探しています。私は本当に知識を独立して適用できるようになりたいと思っています.9章までは、それを行うのに何の問題もありませんでした. でも今 ...

前もって感謝します!

4

4 に答える 4

288

AppleのNSInvocationクラスリファレンスによると:

AnNSInvocationは静的にレンダリングされたObjective-Cメッセージです。つまり、オブジェクトに変換されたアクションです。

そして、もう少し詳しく:

メッセージの概念は、Objective-Cの哲学の中心です。メソッドを呼び出すとき、またはオブジェクトの変数にアクセスするときはいつでも、メッセージを送信します。NSInvocation別の時点でオブジェクトにメッセージを送信したり、同じメッセージを複数回送信したりする場合に便利です。送信するメッセージNSInvocation記述し、後でそれを呼び出す(実際にはターゲットオブジェクトに送信する)ことができます。


たとえば、文字列を配列に追加するとします。通常、addObject:メッセージは次のように送信します。

[myArray addObject:myString];

ここで、NSInvocation別の時点でこのメッセージを送信するために使用するとします。

まず、のセレクターNSInvocationで使用するオブジェクトを準備します。NSMutableArrayaddObject:

NSMethodSignature * mySignature = [NSMutableArray
    instanceMethodSignatureForSelector:@selector(addObject:)];
NSInvocation * myInvocation = [NSInvocation
    invocationWithMethodSignature:mySignature];

次に、メッセージを送信するオブジェクトを指定します。

[myInvocation setTarget:myArray];

そのオブジェクトに送信するメッセージを指定します。

[myInvocation setSelector:@selector(addObject:)];

そして、そのメソッドの引数を入力します。

[myInvocation setArgument:&myString atIndex:2];

オブジェクトの引数はポインタで渡す必要があることに注意してください。それを指摘してくれたRyanMcCuaigに感謝します。詳細については、 Appleのドキュメントを参照してください。

この時点で、myInvocationは完全なオブジェクトであり、送信できるメッセージを記述しています。実際にメッセージを送信するには、次のように呼び出します。

[myInvocation invoke];

この最後のステップにより、メッセージが送信され、基本的には実行され[myArray addObject:myString];ます。

Think of it like sending an email. You open up a new email (NSInvocation object), fill in the address of the person (object) who you want to send it to, type in a message for the recipient (specify a selector and arguments), and then click "send" (call invoke).

See Using NSInvocation for more information. See Using NSInvocation if the above is not working.


NSUndoManager uses NSInvocation objects so that it can reverse commands. Essentially, what you are doing is creating an NSInvocation object to say: "Hey, if you want to undo what I just did, send this message to that object, with these arguments". You give the NSInvocation object to the NSUndoManager, and it adds that object to an array of undoable actions. If the user calls "Undo", NSUndoManager simply looks up the most recent action in the array, and invokes the stored NSInvocation object to perform the necessary action.

See Registering Undo Operations for more details.

于 2008-11-24T05:01:06.030 に答える
49

実際の NSInvocation の簡単な例を次に示します。

- (void)hello:(NSString *)hello world:(NSString *)world
{
    NSLog(@"%@ %@!", hello, world);

    NSMethodSignature *signature  = [self methodSignatureForSelector:_cmd];
    NSInvocation      *invocation = [NSInvocation invocationWithMethodSignature:signature];

    [invocation setTarget:self];                    // index 0 (hidden)
    [invocation setSelector:_cmd];                  // index 1 (hidden)
    [invocation setArgument:&hello atIndex:2];      // index 2
    [invocation setArgument:&world atIndex:3];      // index 3

    // NSTimer's always retain invocation arguments due to their firing delay. Release will occur when the timer invalidates itself.
    [NSTimer scheduledTimerWithTimeInterval:1 invocation:invocation repeats:NO];
}

呼び出されると - [self hello:@"Hello" world:@"world"];- メソッドは次のことを行います。

  • "Hello world!" を印刷します。
  • それ自体の NSMethodSignature を作成します。
  • NSInvocation を作成して入力し、自分自身を呼び出します。
  • NSInvocation を NSTimer に渡す
  • タイマーは (約) 1 秒後に起動し、元の引数でメソッドが再度呼び出されます。
  • 繰り返す。

最終的に、次のような印刷物が得られます。

2010-07-11 17:48:45.262 Your App[2523:a0f] Hello world!
2010-07-11 17:48:46.266 Your App[2523:a0f] Hello world!
2010-07-11 17:48:47.266 Your App[2523:a0f] Hello world!
2010-07-11 17:48:48.267 Your App[2523:a0f] Hello world!
2010-07-11 17:48:49.268 Your App[2523:a0f] Hello world!
2010-07-11 17:48:50.268 Your App[2523:a0f] Hello world!
2010-07-11 17:48:51.269 Your App[2523:a0f] Hello world!
...

もちろん、selfNSTimer が NSInvocation を送信するには、ターゲット オブジェクトが存在し続ける必要があります。たとえば、Singletonオブジェクト、またはアプリケーションの期間中に存在する AppDelegate です。


アップデート:

上記のように、NSInvocation を引数として NSTimer に渡すと、NSTimer は自動的に NSInvocation のすべての引数を保持します。

NSInvocation を引数として NSTimer に渡さず、しばらくそのままにしておきたい場合は、その-retainArgumentsメソッドを呼び出す必要があります。そうしないと、呼び出しが呼び出される前にその引数の割り当てが解除され、最終的にコードがクラッシュする可能性があります。方法は次のとおりです。

NSMethodSignature *signature  = ...;
NSInvocation      *invocation = [NSInvocation invocationWithMethodSignature:signature];
id                arg1        = ...;
id                arg2        = ...;

[invocation setTarget:...];
[invocation setSelector:...];
[invocation setArgument:&arg1 atIndex:2];
[invocation setArgument:&arg2 atIndex:3];

[invocation retainArguments];  // If you do not call this, arg1 and arg2 might be deallocated.

[self someMethodThatInvokesYourInvocationEventually:invocation];
于 2010-07-11T21:57:27.807 に答える
6

こちらのライブラリを使用してみてください。これははるかに優れています。

于 2010-02-02T00:24:00.830 に答える
0

NSInvocation を使用してさまざまなメソッド タイプを呼び出す簡単な例を作成します。

obj_msgSend を使用して複数のパラメーターを呼び出す際に問題が発生しました

https://github.com/clearbrian/NSInvocation_Runtime

于 2014-05-28T15:33:26.040 に答える