NSInvocation For Dummies?

Jak dokładnie działa NSInvocation? Czy jest dobre wprowadzenie?

Mam szczególnie problemy ze zrozumieniem, jak działa poniższy kod (z Cocoa Programming for Mac OS X, 3rd Edition), ale także z możliwością zastosowania tych pojęć niezależnie od próbki samouczka. Kod:

- (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];
}

Rozumiem, co to próbuje zrobić. (BTW, employees jest NSArray klasy custom Person.)

Jako facet z. NET staram się kojarzyć nieznane pojęcia Obj-C i Cocoa z mniej więcej analogiczne koncepcje. NET. Czy jest to podobne do koncepcji delegata. NET, ale nieopisane?

To nie jest w 100% Jasne z książki, więc szukam czegoś uzupełniającego od prawdziwych ekspertów Cocoa / Obj-C, ponownie z celem, że rozumiem podstawowe pojęcie pod prostym (- owskim) przykładem. Naprawdę szukam możliwości samodzielnego zastosowania tej wiedzy . aż do rozdziału 9 nie miałem żadnych trudności z zrobieniem tego. Ale teraz ...

Z góry dzięki!

Author: Chris Hanson, 2008-11-24

4 answers

Według klasy Nsinvocation firmy Apple :

An NSInvocation jest Komunikatem Objective-C renderowanym statycznie, to znaczy jest akcją zamienioną w obiekt.

I, w mały więcej szczegółów:

Pojęcie wiadomości jest centralne dla filozofii objective-C. Za każdym razem, gdy wywołujesz metodę lub uzyskujesz dostęp do zmiennej jakiegoś obiektu, wysyłasz jej wiadomość. NSInvocation przydaje się, gdy chcesz wysłać wiadomość do obiektu na inny punkt w czasie, lub wysłać tę samą wiadomość kilka razy. NSInvocation pozwala opisać wiadomość, którą chcesz wysłać, a następnie wywołać (W rzeczywistości wysłać ją do obiektu docelowego) później.


Na przykład, powiedzmy, że chcesz dodać łańcuch znaków do tablicy. Zazwyczaj wysyłasz addObject: wiadomość w następujący sposób:

[myArray addObject:myString];

Załóżmy, że chcesz użyć NSInvocation, Aby wysłać tę wiadomość w innym momencie:

Po pierwsze, ty przygotowanie obiektu NSInvocation do użycia z selektorem NSMutableArray'S addObject::

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

Następnie należy określić, do którego obiektu ma zostać wysłana wiadomość:

[myInvocation setTarget:myArray];

Określ wiadomość, którą chcesz wysłać do tego obiektu:

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

I podaj wszelkie argumenty dla tej metody:

[myInvocation setArgument:&myString atIndex:2];

Należy zauważyć, że argumenty obiektu muszą być przekazywane przez wskaźnik. Dziękujemy Ryanowi McCuaig za zwrócenie na to uwagi, a więcej informacji można znaleźć w dokumentacji Apple szczegóły.

W tym momencie {[14] } jest kompletnym obiektem, opisującym wiadomość, którą można wysłać. Aby faktycznie wysłać wiadomość, należy zadzwonić:

[myInvocation invoke];

Ten ostatni krok spowoduje wysłanie wiadomości, zasadniczo wykonując [myArray addObject:myString];.

Pomyśl o tym jak o wysłaniu e-maila. Otwierasz nowy adres e-mail (obiektNSInvocation), wpisujesz adres osoby (obiektu), do której chcesz go wysłać, wpisujesz wiadomość dla odbiorcy (podaj selector i argumenty), a następnie klikasz "send" (call invoke).

Zobacz używanie NSInvocation aby uzyskać więcej informacji. Zobacz używanie NSInvocation jeśli powyższe nie działa.


NSUndoManager używa obiektów NSInvocation, dzięki czemu może odwrócić polecenia . Zasadniczo, to, co robisz, to tworzenie NSInvocation obiektu, który powie: "hej, jeśli chcesz cofnąć to, co właśnie zrobiłem, Wyślij tę wiadomość do tego obiektu, z tymi argumentami". Dajemy obiekt NSInvocation NSUndoManager, a on dodaje ten obiekt do tablicy nie do udźwignięcia. Jeśli użytkownik wywoła "Undo", NSUndoManager po prostu wyszukuje ostatnią akcję w tablicy i wywołuje przechowywany obiekt NSInvocation, aby wykonać wymaganą akcję.

Zobacz rejestrowanie operacji cofania Po Więcej Szczegółów.

 273
Author: e.James,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-08-14 21:37:53

Oto prosty przykład NSInvocation w akcji:

- (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];
}

Po wywołaniu - [self hello:@"Hello" world:@"world"]; - metoda będzie:

  • Drukuj " Hello world!"
  • Utwórz dla siebie NSMethodSignature.
  • utworzyć i wypełnić NSInvocation, wywołując się.
  • przekazać NSInvocation do NSTimer
  • timer uruchomi się w około 1 sekundzie, powodując ponowne wywołanie metody z jej oryginalnymi argumentami.
  • powtórz.

In the end, dostaniesz taki wydruk:

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!
...

Oczywiście obiekt docelowy self musi nadal istnieć, aby NSTimer wysłał do niego NSInvocation. Na przykład obiekt Singleton lub AppDelegate, który istnieje przez czas trwania aplikacji.


UPDATE:

Jak wspomniano powyżej, gdy przekazujesz nsinvocation jako argument do Nstimera, NSTimer automatycznie zachowuje wszystkie argumenty NSInvocation.

If you are not passing NSInvocation jako argument dla Nstimera, i planujesz, że zostanie przez jakiś czas, musisz wywołać jego metodę -retainArguments. W przeciwnym razie jego argumenty mogą zostać dealokowane przed wywołaniem wywołania, co ostatecznie spowoduje awarię kodu. Oto jak to zrobić:

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];
 45
Author: Dave Gallagher,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-05-19 15:20:51

Możesz spróbować po prostu skorzystać z biblioteki tutaj, która jest o wiele ładniejsza: http://cocoawithlove.com/2008/03/construct-nsinvocation-for-any-message.html

 5
Author: Casebash,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-02-02 00:24:00

Buduję prosty przykład wywoływania różnych typów metod z NSInvocation.

Miałem problemy z wywołaniem wielu paramów przy użyciu obj_msgSend

Https://github.com/clearbrian/NSInvocation_Runtime

 0
Author: brian.clear,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-05-28 15:33:26