Opóźnione wywołanie metody

Opóźnione wywołanie metody

Czasem pojawia się w aplikacji potrzeba opóźnionego wywołania jakiejś funkcji.
Nie chodzi mi w tym przypadku o proste dispatch_after, czyli coś w stylu

Wyobraźmy sobie następujący przypadek. Mamy aplikację, która umożliwia wyszukiwanie. Użytkownik wpisuje kolejne litery, a aplikacja pyta np. jakieś API o wyniki. Zakładając, że szukam słowa ‚przemek’, mam siedem liter do wpisania. Reagując na każdą literę poprzez wysłanie zapytania do serwera zrobimy sobie krzywdę. A jeżeli nie sobie, to serwerowi. Dobrze by było poczekać chwilę i wysłać zapytanie do serwera w momencie gdy użytkownik przestanie wpisywać kolejne litery. Powiedzmy, po sekundzie od ostatniego znaku.

Przyjmijmy, że mamy jakiś UISearchBar, którego delegatem jest nasz kontroler. Dodatkowo mamy dwie, na razie puste, metody

Pierwszą będziemy wywoływali z naszego delegata, druga będzie robiła prawdziwą robotę. Będzie szukała Przemka ;-).

Każda zmiana „zawartości” searcha spowoduje wywołanie metody
- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText
I tu zrobimy mały trick. Nie będziemy nic szukać. Zamiast tego wywołamy naszą metodę – (void)searchWithDelay:(NSString*)searchString, w której ustawimy timer, który zaczenie szukać za sekundę. Ale zanim ustawimy, sprawdzimy czy już czegoś wcześniej nie zaplanowaliśmy i jeżeli tak, usuniemy to.

Docelowo nasza metoda będzie wyglądała tak:

W linii 3 sprawdzamy czy jakiś cudem nie dostaliśmy nulla. Jeżeli tak, wyskakujemy i nic nie robimy.
Linia 8 to sprawdzenie, czy już wcześniej czegoś nie zaplanowaliśmy. Jeżeli chwilę wcześniej chcieliśmy szukać wyrażenia „prz”, a teraz doszła kolejna litera i chcemy rozejrzeć się za „prze”, to poprzedni rezulatat nas już nie interesuje. Usuwamy więc nasze poprzednie zadanie w linii 10. Sprawdzamy następnie czy jest czego szukać (linia 13) i ustawiamy nowy timer, przekazując także nasz tekst, którego chcemy szukać. w userInfo możemy przekazać praktycznie każdy obiekt, jeżeli chcemi ich przkazać więcej, trzeba je opakować w NSDictionary.

Teraz smutne założenie, użytkownik zasłabł lub z innego powodu (znudziła mu się nasza aplikacja?!?!) przestał wpisywać moje imię… Po jakiejś sekundzie nasz timer wywołuje docelową metodę. Dlaczego jakiejś? iOS zakłada jakąś tolerancję na poziomie 10%. Nie powinniśmy więc stosować tego rozwiązania przy operacji na otwartym sercu. W naszym przypadku jednak nie stanowi to problemu.

Minęła więc ta nasza przysłowiowa sekunda, wywołana jest metoda

W linii 5 sprawdzamy czy jest czego szukać. Jeżeli tak, przystępujemy do działania.

Kod naszego kontolera będzie wyglądał tak

Jeżeli macie jakieś problemy lub nie chce Wam się tego pisać, przykład można pobrać z GitHub. Działanie wygląda tak

Strasznie długi wpis jak na takie proste rozwiązanie. Mam nadzieję, że wszystko jest jasne.

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *