-didSelectRowAtIndexPath: não sendo chamado

295

Estou escrevendo um aplicativo para iOS com uma visualização de tabela em uma visualização de guia. No meu UITableViewController, eu implementei -tableView:didSelectRowAtIndexPath:, mas quando seleciono uma linha em tempo de execução, o método não está sendo chamado. A visualização de tabela está sendo preenchida, portanto, eu sei que outros métodos tableView no meu controlador estão sendo chamados.

Alguém tem alguma idéia do que eu possa ter estragado para fazer isso acontecer?

Matt Pfefferle
fonte
79
Também você pode ter um GestureRecognizer no topo do UITableView que absorve a seleção .. (uma das possibilidades)
M.Othman
Tenha cuidado se a visualização da tabela estiver sendo preenchida, isso significa que o DataSource está bem definido. A seleção faz parte dos métodos de delegação. Talvez o DataSource esteja bem definido, mas não o Delegado!
Thomas Besnehard
1
Olá M.Othman, seu comentário é exatamente o que estava errado com meu próprio problema. Você sabe como obter o gestoRecognizer trabalhando 'com' o UITableView?
yhl 30/09
15
Percebo que, se eu tocar sem soltar, a torneira eventualmente chama -didSelectRowAtIndexPath. Eu descobri o chapéu, porque tenho um reconhecedor de gestos na tela e o gesto precisa falhar antes de receber o toque. Embora seja estranho, a animação de seleção de tabela não é afetada pelo reconhecedor de gestos.
Hlung
6
Eu tive o mesmo problema aqui e tive a oportunidade de saber que você não pode ter um gestoRecognizador no topo do UITableView. Obrigado M. Othman!
precisa saber é o seguinte

Respostas:

97

Parece que talvez a classe não seja a UITableViewDelegateda exibição de tabela, embora deva UITableViewControllerdefinir isso automaticamente.

Alguma chance de você redefinir o delegado para outra classe?

caçador
fonte
7
Descobri que, enquanto meu controlador era um UITableViewController, usei um widget UIViewController antigo simples no UI Builder. Isso não funciona. Quando excluí o widget UIViewController e soltei um UITableViewController em seu lugar, tudo funcionou.
Matt Pfefferle
1
Outro caso de fronteira para todos - eu liguei o delegado em código e esqueci que já havia ligado o delegado através do storyboard .... o último a definir é o vencedor.
Oliver Dungey
1
você pode mostrar como "redefinir um delegado para outra classe", por favor? Eu tenho esse mesmo problema e não consegue resolvê-lo
Alfro
1
myTableViewController.tableView.delegate = xxx
Hunter
534

Apenas no caso de alguém cometer o mesmo erro estúpido que eu:

Verifique se o nome do método que você espera ser didSelectacidentalmente pode ser obtido didDeselectde alguma forma. Demorou cerca de duas horas para eu descobrir ...

Dschee
fonte
47
O mesmo problema aqui. É porque o XCode preenche automaticamente a opção Desmarcar antes do Selecionar.
user1021430
Da mesma forma, eu configurei allowSelection = false, que além de remover qualquer destaque de seleção, também impede que a célula seja pressionada!
djinne95
503

Outra coisa que pode levar ao problema não é o tipo de seleção selecionado:

Tipo de seleção UITableView

Deve ser Single Selectionpara seleção normal, não deve ser No Selection.

Para fazer isso programaticamente, faça:

tableView.allowsSelection = YES
Dennis Krut
fonte
4
Eu continuo me deparando com isso porque tenho cenas que estão sempre no modo de edição e esqueci de alterar o padrão de "Nenhuma seleção durante a edição".
Simétrica
3
Você pode adicionar essa linha no seu método -viewDidLoad do viewControlller NSParameterAssert (self.tableView.allowsSelection);
Nikolay Shubenkov
para aqueles que observaram tableView.rx.itemSelected.subscribe não funcionavam chamada de volta, este é o problema e correção acima obras
Dhilip
tão útil quando você assume o controle de alguma base de código e ele possui código usando botões com tags e não didSelectRow, com essa seleção desabilitada no storyboard #
Nitin Alabur
esse comportamento padrão da tableView?
Frostmourne
296

Outra possibilidade é que um UITapGestureRecognizer possa estar comendo os eventos, como foi o caso aqui: https://stackoverflow.com/a/9248827/214070

Não suspeitei dessa causa, porque as células da tabela ainda destacariam o azul como se as torneiras estivessem passando.

bugloaf
fonte
Este foi o meu problema! Muito obrigado!! Quero dizer, claramente funcionou antes, mas parou de funcionar após a implementação do UITapGestureRecognizer * tap = [[alocação do UITapGestureRecognizer] initWithTarget: self action: @selector (unlockKeyboard)]; [self.view addGestureRecognizer: toque];
coolcool1994
26
Eu tive o mesmo problema que você @ coolcool1994 acabou de implementar [tap setCancelsTouchesInView: NO]; e resolveu o problema.
Nizx
Obrigado, isso me ajuda. No meu caso didSelectRowAtIndexPath, não funciona apenas após excluir a célula commitEditingStyle. Então eu faço UITapGestureRecognizere tapAction:tenho indexPathde sender.view( [self.tableView indexPathForCell:sender.view]) e chamada[self.tableView.delegate didSelectRowAtIndexPath:myIndexPath]
Alexmelyon
1
Este também foi o meu problema .. adicione código para remover a tapgesture na tableview e funcionou como charme - (UITableViewCell *) tableView: (UITableView *) tableView cellForRowAtIndexPath: (NSIndexPath *) indexPath {UITapGestureRecognizer * Gestor = [[UITapGestureRecognizer ] iniciar]; speech.cancelsTouchesInView = NÃO; [self.tableView addGestureRecognizer: gesto]; }
Udaya Sri
6
Obrigado @nizx, em swift 4 tap.cancelsTouchesInView = false
Ariven Nadar
150

Todas as boas respostas, mas há mais uma a procurar ...

(Principalmente ao criar um UITableView programaticamente)

Verifique se o tableView pode responder à seleção definindo [tableView setAllowsSelection:YES];ou removendo qualquer linha que a defina NO.

Old McStopher
fonte
9
Eu gostaria de acrescentar setAllowsSelectionDuringEditing:à lista (quando tableview está no modo de edição)
alex-i
Obrigado! No IB, tive que alterar o valor da seção "Seleção" para Single Selection.
Sasho 31/07
90

Se o problema surgir, UITapGestureRecognizervocê pode corrigir isso:

  • no Storyboard:

insira a descrição da imagem aqui

em código com Objective-C:

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

[tap setCancelsTouchesInView:NO];

em código com Swift:

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

tap.cancelsTouchesInView = false
Bartłomiej Semańczyk
fonte
67

Eu encontrei duas coisas nessas situações.

  1. Você pode ter se esquecido de implementar o protocolo UITableViewDelegate ou não há saída de delegação entre sua classe e sua exibição de tabela.

  2. Você pode ter um UIView em sua linha que é o primeiro a responder e retira seus cliques. Diga um UIButton ou algo semelhante.

gilm
fonte
5
Começou a acontecer no iOS 7, desativando a "Interação do usuário ativada" das visualizações no contentView, corrigiu isso.
Kof
1
@Kof acertou em cheio. Criar um UITableViewCell no construtor de interface do Xcode 5 cria-o com a interação do usuário ativada = YES. Xcode 5 ruim!
Jsd #
44

Eu tive o mesmo problema. E foi difícil de encontrar. Mas em algum lugar do meu código estava este:

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

Deve ser return indexPath, caso contrário, -tableView:didSelectRowAtIndexPath:não está sendo chamado.

JackPearse
fonte
2
para fizeram SelectRow No IndexPath assinatura correta é: - (void) tableView: (UITableView *) tableView didSelectRowAtIndexPath: (NSIndexPath *) indexPath {
coolcool1994
Para mim, ele não iria começar a chamar tableView: didSelectRowAtIndexPath até eu deletei willSelectRowAtIndexPath inteiramente
etayluz
38

Se você adicionou um gestoRecognizador na parte superior do UITableView, didSelectRowAtIndexPathnão será chamado.

Portanto, você precisa usar o método de delegação gestRecognizer para evitar o toque em uma exibição específica.

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {
    if ([touch.view isDescendantOfView:YourTable]) {
        return NO;
    }
    return YES;
}
Vinu David Jose
fonte
3
if ([touch.view isDescendantOfView:YourTable])
Sudheesh
29

Eu encontrei um problema em que, depois de meses sem olhar para o meu código, esqueci que implementei o método a seguir devido a alguns requisitos que não eram necessários

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

Ele deve retornar SIM para uma linha para torná-la selecionada.

cpt.neverm1nd
fonte
24

VOCÊ DEVE selecionar essas opções

insira a descrição da imagem aqui

mas se você não deseja UITableViewdestacar o clique, faça alterações nas UITableViewCellpropriedades.

Escolha a opção Nenhum para a seleção, como abaixo

insira a descrição da imagem aqui

Mohsin Qureshi
fonte
20

Eu tinha colocado uma UITapGestureRecognizervisão na minha mesa para descartar o teclado que impedia didSelectRowAtIndexPath:de ser chamado. Espero que ajude alguém.

Groot
fonte
19

Eu tive o mesmo problema,

O motivo foi o uso de UITapGestureRecognizer. Eu queria que o teclado fosse descartado quando toquei em qualquer outro lugar. Percebi que isso substitui todas as ações de toque, por isso a didSelectRowAtIndexPathfunção não foi chamada.

Quando eu comento as linhas relacionadas UITapGestureRecognizer, ele funciona. Além disso, você pode verificar se a função UITapGestureRecognizer selectortocada é UITableViewCellou não.

Jeyhun Karimov
fonte
14

No meu caso, didSelctRowAtIndexPath não chamando deve-se ao fato de eu ter selecionado nenhum na propriedade Selection do tableView, definido como a seleção única, resolvido o meu problema

insira a descrição da imagem aqui

Ahmad Naveed
fonte
11

Para o Xcode 6.4, Swift 1.2. A seleção "tag" foi alterada no IB. Não sei como e por quê. Configurá-lo para "Seleção única" tornou minhas células de exibição de tabela selecionáveis ​​novamente. insira a descrição da imagem aqui

MB_iOSDeveloper
fonte
10

Mesmo que outra resposta tenha sido aceita, adicionarei mais um possível problema e solução para as pessoas que observam esse problema:

Se você tiver a contagem automática de referência (ARC) ativada, poderá descobrir que, mesmo depois de atribuir seu controlador como delegado da exibição, as mensagens da exibição para o controlador não serão recebidas porque o ARC está excluindo o controlador. Aparentemente, o ponteiro delegado do UITableView não conta como referência para o ARC; portanto, se essa for a única referência a ele, o controlador será desalocado. Você pode verificar se isso está acontecendo ou não, implementando o método dealloc no controlador e definindo um ponto de interrupção ou chamada NSLog lá.

A solução é acompanhar o controlador com uma referência forte em outro lugar, até que você tenha certeza de que não precisará mais dele.

Andrew Gorcester
fonte
O controlador está sendo coletado de lixo enquanto sua visualização ainda é exibida? Isso pode realmente acontecer?
Drux
@Drux Yep! Quando isso aconteceu comigo, era quase a primeira versão do Obj-C com coleta de lixo usada no iOS e, honestamente, eles não fizeram um ótimo trabalho. Muitas referências foram explícitas ou implicitamente "fracas" que, na IMO, deveriam ter sido fortes. O que levou a esquisitices como a coleta de lixo de objetos em uso ativo pela camada de exibição. Não trabalho com o iOS há algum tempo, por isso não faço ideia se isso ainda acontece na versão mais recente.
Andrew Gorcester
Meu código tem um problema crescente de tamanho de memória, e eu o consertei e em algum outro lugar do código logo depois que esse didSelect não será chamado apenas na primeira vez. Não sei se isso justifica o problema ou não.
Amber K
10

Lembre-se de definir a fonte de dados e delegar no método viewDidLoad da seguinte maneira:

[self.tableView setDelegate:self];

[self.tableView setDataSource:self];
Carlos
fonte
Eu estava chamando fonte de dados, mas não delegar ... obrigado!
Gmeister4
9

Meu problema não foi nenhum dos itens acima. E tão coxo. Mas pensei em listá-lo aqui, caso isso ajude alguém.

Eu tenho um tableViewControllerque é meu controlador "base" e, em seguida, crio subclasses desse controlador. Eu estava escrevendo todo o meu código na tableView:didSelectRowAtIndexPathrotina na classe "base". Esquecendo completamente que, por padrão, essa rotina também havia sido criada (embora sem código que fizesse alguma coisa) em todas as minhas subclasses também. Então, quando eu executei meu aplicativo, ele executou a versão da subclasse do código, não fez nada e me deixou triste. Então, é claro, depois que removi a rotina das subclasses, ele usou a rotina de classe mt "base" e estou no negócio.

Eu sei. Não ria Mas talvez isso poupe a alguém a hora que perdi ...

Steve
fonte
8

Dando meus 2 centavos nisso.

Eu tinha um UITableViewCell personalizado e havia um botão cobrindo a célula inteira; portanto, quando o toque aconteceu, o botão foi selecionado e não a célula.

Remova o botão ou, no meu caso, defino a Interação do usuário ativada como false no botão, dessa forma a célula foi a selecionada.

gmogames
fonte
8

Se você ler isso, ainda assim não resolve o problema.

Eu tenho uma célula personalizada , onde a caixa de seleção " Interação do usuário ativada " foi desativada. Então, eu apenas ligo. Boa sorte.

HotJard
fonte
7

Acabei de ter isso e, como aconteceu comigo no passado, não funcionou porque não prestei atenção ao preenchimento automático ao tentar adicionar o método e acabei implementando tableView:didDeselectRowAtIndexPath: em vez de tableView:didSelectRowAtIndexPath:.

user486646
fonte
7

Certifique-se de implementar tableView:didSelectRowAtIndexPathe nãotableView:didDeSelectRowAtIndexPath

Isso me pegou em mais de algumas ocasiões !!

SleepsOnNewspapers
fonte
5

Eu sei que é antigo e o problema foi resolvido, mas tive um problema semelhante, pensei que o problema estava com meu UITableViewCell personalizado, mas a solução era completamente diferente - eu reinicio o XCode :) e depois funciona ok! quase como o Windows :)

Lukasz
fonte
5

Se a visualização da tabela estiver no modo de edição (por exemplo [tableView setEditing:YES animated:NO];), é necessário definirtableView.allowsSelectionDuringEditing = YES;

yvetterowe
fonte
4

Outro erro que você poderia ter cometido (como eu fiz): se você definir um segue na célula, didSelectRowAtIndexPathnão será chamado. Você deve definir seus segues no controlador de exibição.

juanignaciosl
fonte
4

Nenhuma dessas respostas funcionou para mim. Após cerca de uma hora, descobri algo muito traiçoeiro:

Eu tenho uma exibição de tabela dentro de uma célula de outra exibição de tabela. Decidi fazer uma visão anexa que contenha a visão interna da tabela, entre outras coisas. Chamei essa visualização de contentView e liguei-a no xib.

Acontece que o UITableViewCell já tem um contentView e faz coisas estranhas com ele. O problema foi resolvido quando eu renomeei a propriedade para mainContentView e reconecte a exibição a essa propriedade renomeada.

xytor
fonte
4

No meu caso, eu dinamicamente calcular a altura de os TableView's SuperViewno momento do carregamento. Devido a um erro de cálculo, o TableViewfoi posicionado fora do SuperView. A opção TableViewfoi selecionada, no entanto, toda a interação foi desativada (e didSelectRowAtIndexPathnunca foi chamada). Muito difícil de detectar, pois não há indicação visual de que o TableViewitem não seja "acessível".

GK100
fonte
4

No meu caso, o problema era que eu tinha uma UITableViewCellsubclasse e havia implementado esses dois métodos: touchesBegan:withEvent:& touchesEnded:withEventpara lidar com uma animação sofisticada ao toque. Mas eu tinha esquecido de adicionar o [super touchesBegan:touches withEvent:event];anúncio de método [super touchesEnded:touches withEvent:event];para também informar o pai da célula sobre o toque.

Então, alterar o código para o seguinte resolveu meu problema:

-(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
}
alternatiph
fonte
1
Posso confirmar que isso causou o problema do OP para mim em particular
Josh Wolff
4

No meu caso, a solução foi alterar NÃO para SIM na função abaixo.

iOS 9 ou superior

- (BOOL)tableView:(UITableView *)tableView shouldHighlightRowAtIndexPath:(NSIndexPath *)indexPath
{
    return YES;
}
HonkyHonk
fonte
Este também foi o meu problema. Eu tenho uma implementação tableView múltipla e esqueci de separar os dois tableViews neste método.
turingtested