Nadal jestem trochę nowy w Objective-C i zastanawiam się, jaka jest różnica między następującymi dwoma stwierdzeniami?
[object performSelector:@selector(doSomething)];
[object doSomething];
objective-c
selector
dynamic-languages
method-dispatch
Hazardzista
źródło
źródło
performSelector:
jest czymś, co prawdopodobnie robisz tylko wtedy, gdy zaimplementujesz akcję docelową w swojej klasie. RodzeństwoperformSelectorInBackground:withObject:
iperformSelectorOnMainThread:withObject:waitUntilDone:
często są bardziej przydatne. Do tworzenia wątku w tle i do wywoływania wyników z wątku głównego z tego wątku w tle.performSelector
jest również przydatny do pomijania ostrzeżeń kompilacji. Jeśli wiesz, że metoda istnieje (jak po użyciurespondsToSelector
), Xcode przestanie mówić „może nie odpowiadaćyour_selector
”. Po prostu nie używaj go, zamiast znaleźć prawdziwą przyczynę ostrzeżenia. ;)W tym bardzo podstawowym przykładzie w pytaniu
nie ma różnicy w tym, co się wydarzy. Funkcja doSomething zostanie wykonana synchronicznie przez obiekt. Jedynie „doSomething” jest bardzo prostą metodą, która nic nie zwraca i nie wymaga żadnych parametrów.
czy było to coś bardziej skomplikowanego, na przykład:
sprawy by się skomplikowały, ponieważ [obiekt doSomethingWithMyAge: 42];
nie można już wywoływać z żadnym wariantem „performSelector”, ponieważ wszystkie warianty z parametrami akceptują tylko parametry obiektu.
Selektorem w tym miejscu byłoby „doSomethingWithMyAge:”, ale każda próba
po prostu się nie skompiluje. przekazanie NSNumber: @ (42) zamiast 42 też by nie pomogło, ponieważ metoda oczekuje podstawowego typu C, a nie obiektu.
Ponadto istnieją warianty performSelector do 2 parametrów, nie więcej. Chociaż metody wielokrotnie mają o wiele więcej parametrów.
Dowiedziałem się, że chociaż synchroniczne warianty performSelectora:
zawsze zwracał obiekt, mogłem również zwrócić prosty BOOL lub NSUInteger i zadziałało.
Jednym z dwóch głównych zastosowań performSelector jest dynamiczne tworzenie nazwy metody, którą chcesz wykonać, jak wyjaśniono w poprzedniej odpowiedzi. Na przykład
Innym zastosowaniem jest asynchroniczne wysyłanie komunikatu do obiektu, który zostanie wykonany później na bieżącym runloopie. W tym celu istnieje kilka innych wariantów performSelector.
(tak, zebrałem je z kilku kategorii klas Foundation, takich jak NSThread, NSRunLoop i NSObject)
Każdy z wariantów ma swoje specjalne zachowanie, ale wszystkie mają coś wspólnego (przynajmniej wtedy, gdy parametr waitUntilDone ma wartość NIE). Wywołanie „performSelector” zwróciło by się natychmiast, a wiadomość do obiektu zostanie umieszczona w bieżącym runloop dopiero po pewnym czasie.
Z powodu opóźnionego wykonania - naturalnie żadna wartość zwracana nie jest dostępna z metody selektora, stąd wartość zwracana - (void) we wszystkich tych wariantach asynchronicznych.
Mam nadzieję, że jakoś to opisałem ...
źródło
@ennuikiller jest na miejscu. Zasadniczo selektory generowane dynamicznie są przydatne, gdy nie znasz (i zazwyczaj nie możesz) nazwy metody, którą będziesz wywoływać podczas kompilowania kodu.
Jedną kluczową różnicą jest to, że
-performSelector:
i przyjaciele (w tym warianty wielowątkowe i opóźnione ) są nieco ograniczone, ponieważ są zaprojektowane do użytku z metodami z parametrami 0-2. Na przykład wywołanie-outlineView:toolTipForCell:rect:tableColumn:item:mouseLocation:
z 6 parametrami i zwrócenieNSString
jest dość nieporęczne i nie jest obsługiwane przez dostarczone metody.źródło
NSInvocation
obiektu.performSelector:
wszyscy przyjaciele przyjmują argumenty obiektu, co oznacza, że nie można ich używać do wywoływania (na przykład)setAlphaValue:
, ponieważ ich argumentem jest liczba zmiennoprzecinkowa.Selektory są trochę podobne do wskaźników funkcji w innych językach. Używasz ich, gdy nie wiesz w czasie kompilacji, którą metodę chcesz wywołać w czasie wykonywania. Podobnie jak wskaźniki funkcji, zawierają one tylko część czasownika wywołania. Jeśli metoda ma parametry, musisz je również przekazać.
An
NSInvocation
służy podobnemu celowi, z tym wyjątkiem, że wiąże ze sobą więcej informacji. Zawiera nie tylko część czasownika, ale także obiekt docelowy i parametry. Jest to przydatne, gdy chcesz wywołać metodę na określonym obiekcie z określonymi parametrami, nie teraz, ale w przyszłości. Możesz zbudować odpowiedniNSInvocation
i odpalić go później.źródło
Jest jeszcze jedna subtelna różnica między nimi.
Oto fragment dokumentacji Apple
"performSelector: withObject: afterDelay: Wykonuje określony selektor w bieżącym wątku podczas następnego cyklu pętli uruchamiania i po opcjonalnym okresie opóźnienia. Ponieważ czeka na następny cykl pętli uruchamiania, aby wykonać selektor, metody te zapewniają automatyczne mini opóźnienie od aktualnie wykonywany kod. Wiele selektorów w kolejce jest wykonywanych jeden po drugim w kolejności, w jakiej były w kolejce. "
źródło
performSelector:withObject:afterDelay:
, ale pytanie i Twój fragment używająperformSelector:
, co jest zupełnie inną metodą. Z dokumentacji: <quote>performSelector:
Metoda jest równoważna wysłaniuaSelector
wiadomości bezpośrednio do odbiorcy. </quote>performSelector/performSelector:withObject/performSelector:withObject:afterDelay
wszyscy zachowywali się w ten sam sposób, co było błędem.