Objective-C respondsToSelector

Z tego, czego się do tej pory nauczyłem: w Objective-C możesz wysłać dowolną wiadomość do dowolnego obiektu. Jeżeli obiekt zaimplementuje właściwą metodę, zostanie wykonany w przeciwnym razie nic się nie stanie. Dzieje się tak, ponieważ przed wysłaniem wiadomości Objective-C wykona respondsToSelector .

Mam nadzieję, że mam rację.

Zrobiłem mały program do testowania, gdzie akcja jest wywoływana za każdym razem, gdy suwak jest przesuwany. Również do testowania ustawiłem nadawcę na NSButton ale w rzeczywistości jest NSSlider. Teraz zapytałem obiekt, czy odpowie na setAlternateTitle . Podczas gdy NSButton zrobi, a NSSlider nie. Jeśli uruchomię kod i wykonam respondsToSelector sam powie mi, że obiekt nie odpowie na ten selektor. Jeśli przetestuję coś innego jak intValue , odpowie. Jak na razie mój kod jest w porządku.

- (IBAction)sliderDidMove:(id)sender
{
    NSButton *slider = sender;

    BOOL responds =
    [slider respondsToSelector:@selector(setAlternateTitle)];

    if(responds == YES)
    {
        NSLog(@"YES");        
    }
    else
    {
        NSLog(@"NO");
    }

    [slider setAlternateTitle:@"Hello World"];
}

Ale kiedy faktycznie wysyłam wiadomość setAlternateTitle program się zawiesi i nie jestem do końca pewien dlaczego. Czy to nie powinno zrobić respondsToSelector przed wysłaniem wiadomości?

Author: Slipp D. Thompson, 2011-01-01

4 answers

Po pierwsze, nazwa metody (jej selektora) zawiera wszystkie podczęści i znaki dwukropka, jak powiedział mvds.

Po drugie, metoda -respondsToSelector: nie jest wywoływana przez runtime, jest zwykle wywoływana przez użytkownika (siebie lub API, które chcą wiedzieć, czy delegat, na przykład, odpowiada na opcjonalną metodę protokołu).

Podczas wysyłania wiadomości do obiektu, runtime będzie szukał implementacji metody w klasie obiektu (poprzez isa obiektu pointer). Jest to równoznaczne z wysłaniem -respondsToSelector:, chociaż sama wiadomość nie jest wysyłana. Jeśli implementacja metody znajduje się w klasie lub w jej superklasach, jest ona wywoływana ze wszystkimi argumentami, które przekazałeś.

Jeżeli nie, wtedy runtime daje wiadomość drugą szansę do wykonania. Rozpocznie się od wysłania wiadomości + (BOOL)resolveInstanceMethod:(SEL)name do klasy obiektu: metoda ta umożliwia dodanie metody w trybie runtime do klasy: jeżeli ta wiadomość zwróci YES, to znaczy, że może prześlij wiadomość.

Jeśli nie daje trzeciej szansy wykonania wiadomości, wysyła - (id)forwardingTargetForSelector:(SEL)aSelector z selektorem, metoda ta może zwrócić inny obiekt, który może odpowiedzieć selektorowi w imieniu rzeczywistego odbiorcy, jeśli zwrócony obiekt może odpowiedzieć, metoda jest wykonywana i zwracana wartość tak, jakby została zwrócona przez oryginalną wiadomość. (Uwaga: jest to dostępne począwszy od systemu OS X 10.6 lub iOS 4.)

Jeśli zwracanym obiektem jest nil lub self (aby uniknąć infinite loops), runtime daje wiadomość czwartą szansę na wykonanie metody ... wysyła wiadomość - (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector, Aby uzyskać sygnaturę metody w celu zbudowania wywołania. Jeśli takowe jest podane, to wywołanie jest wysyłane za pośrednictwem wiadomości - (void)forwardInvocation:(NSInvocation *)anInvocation. W tej metodzie możesz analizować wywołanie i budować inne wiadomości do wysyłania do innych celów w dowolny sposób, a następnie możesz ustawić wartość zwracaną wywołania ... ta wartość będzie działać jako wartość zwracana oryginału wiadomość.

Na koniec, jeżeli obiekt nie zwraca żadnej sygnatury metody, wtedy runtime wyśle wiadomość - (void)doesNotRecognizeSelector:(SEL)aSelector do obiektu, implementacja tej metody w klasie NSObject rzuci wyjątek.

 148
Author: Psycho,
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
2013-05-11 06:55:47

Po pierwsze, selector jest nie tylko "nazwą" wiadomości, ale także tym, co następuje, tj. argumentami i ich nazwami.

Więc właściwym selektorem dla niektórych -(void)setAlternateTitle:(NSString*)str będzie

@selector(setAlternateTitle:)

z :

Jeśli chodzi o twój problem: jeśli klasa respondsToSelector() i wykonujesz ten selektor, nie powinieneś mieć awarii przy wysyłaniu nieznanego selektora. Jaki rodzaj dziennika awarii widzisz w oknie debugowania?

(ps. dlaczego nie dołączyć [slider setAlternateTitle:...] do if ( responds ) { ... } warunkowego block?)

 7
Author: mvds,
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
2011-01-01 15:19:01

" dzieje się tak dlatego, że przed przesłaniem jest wysłane Objective-C wykona respondsToSelector."

To chyba nie jest poprawne. Jeśli obiekt nie odpowie na selektor, ulegnie awarii w czasie wykonywania. Nie ma automatycznego sprawdzania przez system. Jeśli system czasu pracy był sprawdzany, to nigdy nie powinniśmy otrzymywać wyjątku "nierozpoznany selektor wysłany do instancji". Proszę, popraw mnie, jeśli się mylę.

EDIT: to nie jest prosta awaria, ale domyślnym wynikiem jest to, że proces zostanie zakończony. Cała sekwencja jest już wyjaśniona w komentarzu i innych odpowiedziach, więc nie będę pisał tego ponownie.

 2
Author: taskinoor,
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
2015-05-13 00:42:10

Istnieje metoda +instancesRespondToSelector:. Jak sama nazwa wskazuje, mówi ci, czy instancje klasy implementują tę metodę.

 2
Author: Nicolas Miari,
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
2015-12-24 05:06:33