-didSelectRowAtIndexPath: nie jest wywoływany

295

Piszę aplikację na iOS z widokiem tabeli w widoku karty. W moim przypadku UITableViewControllerzaimplementowałem -tableView:didSelectRowAtIndexPath:, ale kiedy wybieram wiersz w czasie wykonywania, metoda nie jest wywoływana. Widok tabeli jest jednak zapełniany, więc wiem, że wywoływane są inne metody tableView w moim kontrolerze.

Czy ktoś ma jakieś pomysły, co spieprzyłem, aby tak się stało?

Matt Pfefferle
źródło
79
również możesz mieć gestRecognizer na UITableView, który absorbuje zaznaczenie .. (jedna z możliwości)
M.Othman
Uważaj, jeśli widok tabeli jest zapełniany, oznacza to, że DataSource jest dobrze ustawiony. Wybór jest częścią metod delegowania. Więc może DataSource jest dobrze ustawiony, ale nie Delegat!
Thomas Besnehard
1
Cześć M.Othman, twój komentarz jest dokładnie tym, co było nie tak z moim problemem. Czy wiesz, jak sprawić, by gestRecognizer działał „z” UITableView?
yhl
15
Zauważam, że jeśli stuknę i przytrzymam, stuknięcie ostatecznie zadzwoni -didSelectRowAtIndexPath. Zrozumiałem czapkę, ponieważ mam widok rozpoznawania gestów w widoku stołu i gest musi zawieść najpierw przed dotknięciem. Rozpoznawanie gestów nie wpływa na animację wyboru stołu.
Hlung
6
Miałem tutaj ten sam problem i miałem szczęście dowiedzieć się, że nie można wykonać gestu Recognizer na UITableView. Dzięki M. Othman!
vnchopra

Odpowiedzi:

97

Wygląda na to, że klasa nie jest odpowiednia UITableViewDelegatedo tego widoku tabeli, choć UITableViewControllerpowinna to ustawić automatycznie.

Czy jest jakaś szansa, że ​​przywrócisz delegata do innej klasy?

Łowca
źródło
7
Odkryłem, że chociaż mój kontroler był UITableViewController, użyłem zwykłego starego widżetu UIViewController w UI Builder. To nie działa. Kiedy usunąłem widget UIViewController i upuściłem UITableViewController na jego miejscu, wszystko działało.
Matt Pfefferle,
1
Kolejna sprawa graniczna dla wszystkich - podłączyłem delegata kodem i zapomniałem, że wcześniej podłączyłem delegata za pośrednictwem scenorysu ... ostatni, aby go ustawić, wygrywa.
Oliver Dungey,
1
czy możesz pokazać, jak „zresetować delegata do innej klasy”? Mam ten sam problem i nie mogę go rozwiązać
Alfro,
1
myTableViewController.tableView.delegate = xxx
Hunter
534

Na wypadek, gdyby ktoś popełnił ten sam głupi błąd, co ja:

Sprawdź, czy nazwa metody, której się spodziewasz, didSelectmoże zostać przypadkowo uzyskana didDeselect. Dowiedziałem się około dwóch godzin ...

Dschee
źródło
47
Ten sam problem tutaj. Jest tak, ponieważ XCode automatycznie uzupełnia Odznacz przed Wybierz.
user1021430
Podobnie, ustawiłem parametr allowSelection = false, który oprócz usunięcia podświetlenia zaznaczenia zapobiega również naciskaniu komórki!
djinne95
503

Inną rzeczą, która może prowadzić do problemu, jest nie wybrany rodzaj wyboru:

Rodzaj wyboru UITableView

Powinien być Single Selectiondo normalnego wyboru, nie powinien być No Selection.

Aby to zrobić programowo, wykonaj:

tableView.allowsSelection = YES
Dennis Krut
źródło
4
Ciągle się na to natrafiam, ponieważ mam sceny, które są zawsze w trybie edycji i ciągle zapominam o zmianie domyślnej z „Brak wyboru podczas edycji”.
Symetryczny
3
Możesz dodać ten wiersz w metodzie -viewDidLoad metody viewControlller NSParameterAssert (self.tableView.allowsSelection);
Nikolay Shubenkov
dla tych, którzy obserwowali tableView.rx.itemSelected.subscribe nie oddzwonili, to jest problem i powyższe poprawki działają
Dhilip
tak pomocne, gdy przejmujesz bazę kodu i ma ona kod za pomocą przycisków z tagami, a nie didSelectRow, z tym zaznaczeniem wyłączonym w serii ujęć 🙄
Nitin Alabur 30.01.2019
czy to zachowanie tableView jest domyślne?
Frostmourne
296

Inną możliwością jest to, że UITapGestureRecognizer może jeść wydarzenia, jak miało to miejsce tutaj: https://stackoverflow.com/a/9248827/214070

Nie podejrzewałem tej przyczyny, ponieważ komórki tabeli nadal podświetlałyby się na niebiesko, jakby krany się przedostawały.

bugloaf
źródło
To był mój problem! Dziękuję bardzo!! Mam na myśli, że wcześniej działał wyraźnie, ale przestał działać po tym, jak zaimplementowałem UITapGestureRecognizer * tap = [[UITapGestureRecognizer przydziel]] initWithTarget: self action: @selector (dismissKeyboard)]; [self.view addGestureRecognizer: dotknij];
coolcool1994
26
Miałem ten sam problem, co Ty zaimplementowałeś właśnie @ coolcool1994 [dotknij setCancelsTouchesInView: NO]; i rozwiązałem problem.
nizx
Dziękuję, to mi pomaga. W moim przypadku didSelectRowAtIndexPathnie działa tylko po usunięciu komórki w commitEditingStyle. Następnie robię UITapGestureRecognizeri tapAction:dostał indexPathod sender.view( [self.tableView indexPathForCell:sender.view]) i wywołanie[self.tableView.delegate didSelectRowAtIndexPath:myIndexPath]
Alexmelyon
1
To też był mój problem. Dodaj kod, aby usunąć tapesture w widoku tabeli i działało to jak urok - (UITableViewCell *) tableView: (UITableView *) tableView cellForRowAtIndexPath: (NSIndexPath *) indexPath {UITapGestureRecognizer * gest = [[UITapGestureRecognizer ] w tym]; gest.cancelsTouchesInView = NO; [self.tableView addGestureRecognizer: gest]; }
Udaya Sri
6
Dzięki @nizx, w szybkim 4 tap.cancelsTouchesInView = false
Ariven Nadar
150

Wszystkie dobre odpowiedzi, ale jest jeszcze jedna rzecz, na którą należy zwrócić uwagę ...

(W szczególności przy programowym tworzeniu UITableView)

Upewnij się, że tableView może zareagować na wybór, ustawiając [tableView setAllowsSelection:YES];lub usuwając linię, która go ustawia NO.

rev Old McStopher
źródło
9
Dodałbym setAllowsSelectionDuringEditing:do listy (gdy widok tabeli jest w trybie edycji)
alex-i
Dziękuję Ci! W IB musiałem zmienić wartość w sekcji „Wybór” na Single Selection.
Sasho,
90

Jeśli pojawi się problem, UITapGestureRecognizermożesz to naprawić:

  • w Storyboard:

wprowadź opis zdjęcia tutaj

w kodzie z Objective-C:

UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(dismissKeyboard)]; 
[self.view addGestureRecognizer:tap];

[tap setCancelsTouchesInView:NO];

w kodzie z Swift:

let tap = UITapGestureRecognizer(target: self, action:Selector("dismissKeyboard"))
view.addGestureRecognizer(tap)

tap.cancelsTouchesInView = false
Bartłomiej Semańczyk
źródło
67

W takich sytuacjach spotkałem dwie rzeczy.

  1. Możliwe, że zapomniałeś wdrożyć protokół UITableViewDelegate lub nie ma punktu delegacji między klasą a widokiem tabeli.

  2. Możesz mieć UIView w swoim rzędzie, który jest pierwszym respondentem i zabiera kliknięcia. Powiedz przycisk UIB lub coś podobnego.

gilm
źródło
5
Zaczęło się to dziać na iOS 7, wyłączenie „Interakcja użytkownika włączona” widoków w contentView rozwiązało to.
Kof
1
@ Kof przybił go. Utworzenie UITableViewCell w kreatorze interfejsu Xcode 5 tworzy go z włączoną interakcją użytkownika = TAK. Zły Xcode 5!
jsd 10.10.2013
44

Miałem ten sam problem. I trudno było znaleźć. Ale gdzieś w moim kodzie było to:

- (NSIndexPath *)tableView:(UITableView *)tableView willSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    return nil;
}

Musi być return indexPath, inaczej -tableView:didSelectRowAtIndexPath:nie zostanie powołany.

JackPearse
źródło
2
dla did SelectRow At IndexPath poprawny podpis to: - (void) tableView: (UITableView *) tableView didSelectRowAtIndexPath: (NSIndexPath *) indexPath {
coolcool1994
Dla mnie nie zacząłbym wywoływać tableView: didSelectRowAtIndexPath, dopóki nie usunę całkowicie
willSelectRowAtIndexPath
38

Jeśli dodałeś gestRecognizer na UITableView, didSelectRowAtIndexPath nie zostanie wywołany.

Musisz więc użyć metody delegowania gestRecognizer, aby uniknąć dotyku w określonym widoku.

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {
    if ([touch.view isDescendantOfView:YourTable]) {
        return NO;
    }
    return YES;
}
Vinu David Jose
źródło
3
if ([touch.view isDescendantOfView:YourTable])
Sudheesh,
29

Wystąpił problem polegający na tym, że po miesiącach nie patrzenia na mój kod zapomniałem, że wdrożyłem następującą metodę z powodu niektórych wymagań, które nie były konieczne

- (BOOL)tableView:(UITableView *)tableView shouldHighlightRowAtIndexPath:(NSIndexPath  *)indexPath{
    return NO;
}

Aby wiersz został wybrany, powinien zwracać TAK.

cpt.neverm1nd
źródło
24

MUSISZ wybrać te opcje

wprowadź opis zdjęcia tutaj

ale jeśli chcesz, aby UITableViewkliknięcie nie było podświetlane, powinieneś wprowadzić zmiany we UITableViewCellwłaściwościach.

Wybierz opcję Brak dla opcji Wybór, tak jak poniżej

wprowadź opis zdjęcia tutaj

Mohsin Qureshi
źródło
20

Położyłem UITapGestureRecognizerwidok na stole, aby zwolnić klawiaturę, która uniemożliwiła didSelectRowAtIndexPath:wywołanie. Mam nadzieję, że to komuś pomoże.

Groot
źródło
19

Miałem ten sam problem

Powodem było użycie UITapGestureRecognizer. Chciałem zamknąć klawiaturę, kiedy stuknąłem gdziekolwiek indziej. Uświadomiłem sobie, że to nadpisuje wszystkie akcje z kranu, dlategodidSelectRowAtIndexPath funkcja nie została wywołana.

Kiedy komentuję powiązane wiersze UITapGestureRecognizer, działa. Ponadto możesz sprawdzić, UITapGestureRecognizer selectorczy podsłuch jest wciśnięty, UITableViewCellczy nie.

Jeyhun Karimov
źródło
14

W moim przypadku, didSelctRowAtIndexPath niestawienie wynika, że wybrano żadnego w Doboru własności Tableview, zestaw do pojedynczego wyboru rozwiązać mój problem

wprowadź opis zdjęcia tutaj

Naveed Ahmad
źródło
11

Dla Xcode 6.4, Swift 1.2. „Tag” wyboru został zmieniony w IB. Nie wiem jak i dlaczego. Ustawienie go na „Pojedynczy wybór” sprawiło, że moje komórki widoku tabeli można ponownie wybrać. wprowadź opis zdjęcia tutaj

MB_iOSDeveloper
źródło
10

Mimo że inna odpowiedź została zaakceptowana, dodam jeszcze jeden możliwy problem i rozwiązanie dla osób, które zauważą ten problem:

Jeśli masz włączone automatyczne zliczanie referencji (ARC), może się okazać, że nawet po przypisaniu kontrolera jako delegata widoku, wiadomości widoku do kontrolera nie są odbierane, ponieważ ARC usuwa kontroler. Najwyraźniej wskaźnik delegowania UITableView nie jest liczony jako odwołanie do ARC, więc jeśli jest to jedyne odniesienie, kontroler zostanie zwolniony. Możesz sprawdzić, czy tak się dzieje, implementując metodę dealloc na kontrolerze i ustawiając tam punkt przerwania lub wywołanie NSLog.

Rozwiązaniem jest śledzenie kontrolera z silnym odniesieniem w innym miejscu, dopóki nie będziesz pewien, że już go nie potrzebujesz.

Andrew Gorcester
źródło
Kontroler jest zbierany, gdy jego widok jest nadal wyświetlany? Czy to może się zdarzyć?
Drux
@Drux Tak! Kiedy mi się to przydarzyło, była to prawie pierwsza wersja Obj-C z funkcją odśmiecania używaną na iOS i szczerze mówiąc, nie spisali się zbyt dobrze. Wiele odniesień było wyraźnie lub pośrednio „słabych”, które, IMO, powinny były być mocne. Doprowadziło to do dziwności, takich jak wyrzucanie elementów bezużytecznych obiektów w aktywnym użyciu przez warstwę wyświetlania. Od jakiegoś czasu nie pracowałem na iOS, więc nie mam pojęcia, czy nadal tak się dzieje w najnowszej wersji.
Andrew Gorcester,
Mój kod ma coraz większy problem z pamięcią i naprawiłem go trochę i gdzieś indziej w kodzie tuż po tym, jak didSelect nie zostanie wywołany tylko za pierwszym razem. Nie wiem, czy to uzasadnia problem, czy nie.
Amber K
10

Pamiętaj, aby ustawić źródło danych i delegować w metodzie viewDidLoad w następujący sposób:

[self.tableView setDelegate:self];

[self.tableView setDataSource:self];
Carlos
źródło
Dzwoniłem do źródła danych, ale nie delegowałem ... dzięki!
Gmeister4
9

Moim problemem nie był żaden z powyższych. I taki kiepski. Ale pomyślałem, że wymienię to tutaj, na wypadek, gdyby komuś to pomogło.

Mam tableViewControllerkontroler „podstawowy”, a następnie tworzę podklasy tego kontrolera. Cały mój kod zapisywałem tableView:didSelectRowAtIndexPathrutynowo w klasie „podstawowej”. Całkowicie zapominając, że domyślnie ta procedura również została stworzona (choć bez kodu, który nic nie zrobiłby) we wszystkich moich podklasach. Więc kiedy uruchomiłem moją aplikację, uruchomiłem wersję podklasy kodu, nic nie zrobiłem i zasmuciło mnie. Więc oczywiście, kiedy usunąłem procedurę z podklas, użyłem procedury klasy mt „base” i jestem w biznesie.

Wiem. Nie śmiej się Ale może to uratuje kogoś straconą godzinę ...

Steve
źródło
8

Dając za to moje 2 centy.

Miałem niestandardowe UITableViewCell i był przycisk pokrywający całą komórkę, więc kiedy nastąpił dotyk, przycisk został wybrany, a nie komórka.

Albo usuń przycisk, albo w moim przypadku ustawiłem opcję Włącz interakcję użytkownika na wartość false, w ten sposób wybrana została komórka.

gmogames
źródło
8

Jeśli to przeczytasz, nadal nie rozwiążesz problemu.

Mam komórkę niestandardową , w której pole wyboru „ Interakcja użytkownika włączona ” było wyłączone. Więc po prostu go włączam. Powodzenia.

HotJard
źródło
7

Właśnie to miałem i jak mi się przydarzyło w przeszłości, to nie działało, ponieważ nie zwracałem uwagi na autouzupełnianie podczas próby dodania metody, a tak naprawdę kończę na implementacji tableView:didDeselectRowAtIndexPath: zamiast tableView:didSelectRowAtIndexPath:.

użytkowników486646
źródło
7

Upewnij się, że został wdrożony tableView:didSelectRowAtIndexPath a nietableView:didDeSelectRowAtIndexPath

Dostałem to więcej niż kilka razy !!

SleepsOnNewspapers
źródło
5

Wiem, że jest stary i problem został rozwiązany, ale miał podobny problem, myślałem, że problem dotyczy mojego niestandardowego UITableViewCell, ale rozwiązanie było zupełnie inne - ponownie uruchamiam XCode :), a następnie działa dobrze! prawie jak Windows :)

Łukasz
źródło
5

Jeśli widok tabeli jest w trybie edycji (np. [tableView setEditing:YES animated:NO];), Musisz ustawićtableView.allowsSelectionDuringEditing = YES;

yvetterowe
źródło
4

Kolejny błąd, który mogłeś popełnić (tak jak ja): jeśli ustawisz segue w komórce, didSelectRowAtIndexPathnie jest wywoływany. Zamiast tego powinieneś ustawić swoje sekwencje na kontrolerze widoku.

juanignaciosl
źródło
4

Żadna z tych odpowiedzi nie działała dla mnie. Po około godzinie wymyśliłem coś bardzo podstępnego:

Mam widok tabeli wewnątrz komórki innego widoku tabeli. Postanowiłem zrobić widok obejmujący między innymi widok wewnętrznego stołu. Nazwałem ten widok contentView i podłączyłem go do xib.

Okazuje się, że UITableViewCell ma już contentView i robi z nim dziwne rzeczy. Problem rozwiązał się, gdy zmieniłem nazwę właściwości na mainContentView i ponownie podłączyłem widok do tej właściwości o zmienionej nazwie.

Xytor
źródło
4

W moim przypadku, dynamicznie obliczyć wysokość TableView„s SuperVieww czasie ładowania. Z powodu błędnej kalkulacji TableViewzostał umieszczony poza SuperView. TableViewZostał sporządzony grzywny, jednak wszystko interakcja była wyłączona (i didSelectRowAtIndexPathnigdy nie został powołany). Bardzo trudny do wykrycia, ponieważ nie ma wizualnego wskazania, że TableViewnie jest „dostępny”.

GK100
źródło
4

W moim przypadku problem polegał na tym, że miałem UITableViewCellpodklasę i zaimplementowałem dwie metody: touchesBegan:withEvent:i touchesEnded:withEventobsługiwać fantazyjną animację dotykową. Ale zapomniałem dodać [super touchesBegan:touches withEvent:event];reklamę metody, [super touchesEnded:touches withEvent:event];aby poinformować również rodzica komórki o dotyku.

Tak więc zmiana kodu na następujący rozwiązała mój problem:

-(void) touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event{
    [super touchesBegan:touches withEvent:event];
    //blah blah blah
}

-(void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{
    [super touchesEnded:touches withEvent:event];
    //rest of the code
}
alternatif
źródło
1
Potwierdzam, że spowodowało to w szczególności problem OP
Josh Wolff
4

W moim przypadku rozwiązaniem była zmiana NIE na TAK w poniższej funkcji.

iOS 9+

- (BOOL)tableView:(UITableView *)tableView shouldHighlightRowAtIndexPath:(NSIndexPath *)indexPath
{
    return YES;
}
HonkyHonk
źródło
To też był mój problem. Mam wiele implementacji tableView i zapomniałem rozdzielić dwa tableViews w tej metodzie.
przetestowane w turing