Erro "seletor não reconhecido enviado à instância" no Objective-C

155

Criei um botão e adicionei uma ação a ele, mas, assim que foi chamado, recebi este erro:

-[NSCFDictionary numberButtonClick:]: unrecognized selector sent to instance
 0x3d03ac0 2010-03-16 22:23:58.811
 Money[8056:207] *** Terminating app
 due to uncaught exception
 'NSInvalidArgumentException', reason:'*** -[NSCFDictionary numberButtonClick:]:  unrecognized selector sent to instance 0x3d03ac0'

Este é o meu código:

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
    if (self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]) {
        UIButton *numberButton = [UIButton buttonWithType:UIButtonTypeCustom];        
        numberButton.frame = CGRectMake(10, 435, 46, 38);
        [numberButton setImage:[UIImage imageNamed:@"one.png"] forState:UIControlStateNormal];
        [numberButton addTarget:self action:@selector(numberButtonClick:) forControlEvents:UIControlEventTouchUpInside];
        [self.view addSubview: numberButton]; 
    }
return self;
}

-(IBAction)numberButtonClick:(id)sender{
    NSLog(@"---");
}
Olá Mundo
fonte

Respostas:

187

Parece que você não está gerenciando adequadamente o controlador de exibição de memória e está sendo desalocado em algum momento - o que faz com que o numberButtonClicked:método seja enviado para outro objeto que agora ocupa a memória que o controlador de exibição estava ocupando ...

Verifique se você está mantendo / liberando corretamente o seu controlador de exibição.

Jasarien
fonte
105
Esse é um diagnóstico muito astuto de poucas linhas de código.
Michael Morrison
41
OK, então o problema foi identificado ... mas "Verifique se está mantendo / liberando corretamente o seu controlador de exibição". é uma sugestão, não uma solução.
Alex Gray
12
@alex cinza, o que? O gerenciamento adequado de memória no controlador de exibição resolveu o problema ... Não entendo como isso não é uma solução?
Jasarien 02/09/11
28
corrigir. embora isso pareça ser "a correção" .. e eu possa estar em minoria (embora eu ainda consiga existir), mas a conexão entre o problema e a solução não é imediatamente óbvia. por exemplo, eu estou encontrando -[NSWindow end]: unrecognized selector sent to instance 0x100523e80 e, apesar de eu perceber as semelhanças com o OP, e até mesmo, possivelmente, a causa de problema de sua resposta, a implementação de uma correção não é imediatamente óbvio
Alex Gray
12
É imediatamente óbvio. O gerenciamento de memória do NSWindow não está correto em algum lugar da linha. Passe pelo seu ciclo de vida e corrija-o.
Jasarien
127

Para quem chega aqui pelo Google como eu, o que provavelmente se refere mais ao Xcode 4.2 + / iOS 5+, o que é o ARC. Eu tive o mesmo erro " seletor não reconhecido enviado para a instância ". No meu caso, eu tinha uma ação de destino do UIButton configurada para passar a si mesma como o parâmetro sender, mas depois percebi que não precisava disso e removi isso no código. Então, algo como:

- (IBAction)buttonPressed:(UIButton *)sender {

Foi alterado para:

- (IBAction)buttonPressed {

Clicar com o botão direito do mouse no UIButton em questão mostrou que o evento Retoque interno estava associado ao método buttonPressed: dos controladores de exibição. Remover isso e reatribuí-lo ao método modificado funcionou muito bem.

LeonardChallis
fonte
Isso foi muito útil, embora eu ache que sua própria pergunta e resposta facilitariam a localização.
Curtis Inderwiesche 29/03/12
@LeonardChallis Como você pode fazer referência ao remetente em buttonPressed se não for passado como parâmetro?
Zakdances
8
Resposta muito útil. Acabei de encontrar esse problema exato e sua solução estava exatamente correta. Estava seguindo a aula de Stanford iOS no iTunesU quando isso aconteceu. Mais uma vez obrigado pela sua resposta!
Marshall Alsup
1
@LeonardChallis Thanks. Eu adicionei uma resposta complementar à sua resposta.
1,21 gigawatts 05/03
1
Eu estava apenas lutando com um problema semelhante, removi o parâmetro remetente da função seletor e depois me perguntei como obter o remetente. No meu caso, estava recebendo o erro porque esqueci de colocar dois pontos após o retorno de chamada do seletor, causando uma incompatibilidade na sequência de chamadas. Com os dois pontos, posso manter o argumento do remetente.
74

Esta foi a principal resposta do Google para esse problema, mas eu tinha uma causa / resultado diferente - pensei em adicionar meus dois centavos caso outras pessoas se deparem com esse problema.

Eu tive um problema semelhante esta manhã. Descobri que, se você clicar com o botão direito do mouse no item da interface do usuário com o problema, poderá ver quais conexões foram criadas. No meu caso, eu tinha um botão conectado até duas ações. Excluí as ações do menu do botão direito e as religuei, e meu problema foi corrigido.

Portanto, certifique-se de que suas ações estão corretamente montadas.

Chris K
fonte
Este foi o meu problema. Renomeei uma função e mudei meu código, mas não mudei a conexão no arquivo xib.
BFTrick 13/09/12
2
OBRIGADO! Aconteceu que eu tinha três métodos que havia excluído ainda referenciados. Me incomodando por uma semana!
Erdekhayser
25

OK, eu tenho que entrar aqui. O OP criou dinamicamente o botão . Eu tive um problema semelhante e a resposta (após horas de caça) é tão simples que me deixou doente.

Ao usar:

action:@selector(xxxButtonClick:)

or (as in my case)

action:NSSelectorFromString([[NSString alloc] initWithFormat:@"%@BtnTui:", name.lowercaseString])

Se você colocar dois pontos no final da string - passará o remetente. Se você não colocar os dois pontos no final da string, isso não ocorrerá e o receptor receberá um erro se espera um. É fácil perder os dois pontos se você estiver criando dinamicamente o nome do evento.

As opções de código do receptor são assim:

- (void)doneBtnTui:(id)sender {
  NSLog(@"Done Button - with sender");
}
 or
- (void)doneBtnTui {
  NSLog(@"Done Button - no sender");
}

Como sempre, é sempre a resposta óbvia que se perde.

Craig H.
fonte
1
Muito obrigado! Esse foi o meu problema (não colocar dois pontos ':' no final do nome do seletor). Como é que quase sempre são as coisas mais estúpidas e simples que fazem os geeks baterem a cabeça contra a parede às 3 da manhã? MUITO OBRIGADO!
TWright
23

No meu caso, a função não esperava um argumento, mas o botão foi configurado para enviar um que causasse o erro. Para consertar isso, tive que religar o manipulador de eventos.

Aqui está a minha função:

insira a descrição da imagem aqui

Observe que ele não contém argumentos.

Aqui está uma imagem da minha configuração de botão (clique com o botão direito do mouse no botão para visualizá-lo):

insira a descrição da imagem aqui

Observe que existem 3 manipuladores de eventos.

Para consertar isso, tive que remover cada um dos itens do evento, pois um deles estava enviando uma referência para a função enterPressed. Para remover esses itens, cliquei no pequeno ícone x ao lado do nome de cada item até que nenhum item fosse mostrado.

insira a descrição da imagem aqui

Em seguida, tive que reconectar o botão ao evento. Para fazer isso, mantenha pressionada a tecla Control e arraste uma linha do botão para a ação. Deve dizer "Ação de conexão". Nota: tive que reiniciar o XCode para que isso funcionasse por algum motivo; caso contrário, deixe-me inserir ações (também conhecidas como criar uma nova ação) acima ou abaixo da função.

insira a descrição da imagem aqui

Agora você deve ter um único manipulador de eventos conectado ao evento button que não passa argumentos:

insira a descrição da imagem aqui

Esta resposta complementa a resposta de @Leonard Challis, que você também deve ler.

1,21 gigawatts
fonte
14

Isso também pode acontecer se você não definir a "Classe" da visualização no construtor de interfaces.

user1658373
fonte
Agh obrigado! Isso estava fazendo com que meu aplicativo travasse em uma sequência, apenas esqueci de definir a classe do controlador.
Eichhörnchen
Por que ele precisa conhecer a classe? Estou tentando usar um UITableViewSection como um UIView e, portanto, estou recebendo esse erro. O compilador diz que UITableViewSection não existe, portanto presumo que seja interno ao UIKit.
Ian Warburton
13

No meu caso, eu estava usando o NSNotificationCenter e estava tentando usar um seletor que não recebeu argumentos, mas estava adicionando dois pontos. A remoção do cólon corrigiu o problema.

Ao usar um nome de seletor, não use dois pontos à direita se não houver argumentos. Se houver um argumento, use dois pontos à direita. Se houver mais de um argumento, você deverá nomeá-los juntamente com dois pontos à direita para cada argumento.

Veja a resposta de Adam Rosenfield aqui: Seletores em Objective-C?

Nathan Garabedian
fonte
11

Eu tive esse problema com um projeto Swift, no qual estou criando os botões dinamicamente. Código do problema:

var trashBarButtonItem: UIBarButtonItem {
    return UIBarButtonItem(barButtonSystemItem: .Add, target: self, action: "newButtonClicked")
}

func newButtonClicked(barButtonItem: UIBarButtonItem) {
    NSLog("A bar button item on the default toolbar was clicked: \(barButtonItem).")
}

A solução foi adicionar dois pontos completos ':' após a ação: por exemplo

var trashBarButtonItem: UIBarButtonItem {
        return UIBarButtonItem(barButtonSystemItem: .Add, target: self, action: "newButtonClicked:")
    }

    func newButtonClicked(barButtonItem: UIBarButtonItem) {
        NSLog("A bar button item on the default toolbar was clicked: \(barButtonItem).")
    }

Exemplo completo aqui: https://developer.apple.com/library/content/samplecode/UICatalog/Listings/Swift_UIKitCatalog_DefaultToolbarViewController_swift.html

FredL
fonte
Logo após seguir o tutorial e ler uma dica sobre exatamente esse mesmo problema - eu me apaixonei por isso: D
user2161301
6

A causa mais óbvia disso (incluída para a integridade) é lançar incorretamente um ponteiro e chamar um método da classe errada.

NSArray* array = [[NSArray alloc] init];
[(NSDictionary*)array objectForKey: key]; // array is not a dictionary, hence exception
devios1
fonte
Esta é uma boa dica - não subclasse uma vista ou dados de objeto (por exemplo, ao não adicionar o nome subclasse) é uma outra maneira isso acontece
Brad M
4

Eu também tive o mesmo problema.

Eu apaguei meu uibutton no meu storyboard e o recriei .. agora tudo funciona bem.

Yohan Dahmani
fonte
3

Eu tive um problema semelhante, mas para mim a solução foi um pouco diferente. No meu caso, usei uma categoria para estender uma classe existente (UIImage para alguns recursos de redimensionamento - veja este tutorial no caso de você estar interessado) e esqueci de adicionar o arquivo * .m ao destino da compilação. Erro estúpido, mas nem sempre óbvio quando acontece onde procurar. Eu pensei que vale a pena compartilhar ...

Mirko Jahn
fonte
3

Isso aconteceu comigo porque, acidentalmente, apague a "@IBAction func ..." dentro do meu código de classe UIViewcontroller, de modo que no Storyboard foi criado o Reference Outlet, mas em tempo de execução havia qualquer função para processá-lo.

A solução foi excluir a referência de saída dentro do inspetor de propriedades e, em seguida, recriá-la, arrastando com a chave de comando o código da classe.

Espero que ajude!

Guillermo
fonte
Da mesma forma, isso também aconteceu comigo quando o botão referenciou uma função que não existia mais.
21718 Josh Wolff
2

Eu acho que você deve usar o vazio, em vez do IBAction no tipo de retorno. porque você definiu um botão programaticamente.

Fa.Shapouri
fonte
2

Outra solução possível: adicione '-ObjC' aos argumentos do vinculador.

A explicação completa está aqui: Categorias de Objective-C na biblioteca estática

Eu acho que a essência é: se a categoria é definida em uma biblioteca com a qual você está vinculando estaticamente, o vinculador não é inteligente o suficiente para vincular os métodos da categoria. O sinalizador acima cria o linker em todas as classes e categorias C objetivas, e não apenas nas que ele julga necessário, com base na análise de sua fonte. (Por favor, sinta-se à vontade para ajustar ou corrigir essa resposta. Conheço idiomas vinculados, por isso estou apenas repetindo aqui).

Russ Egan
fonte
2

Eu tive o mesmo erro e descobri o seguinte:

Quando você usa o código

[self.refreshControl addTarget:self action:@selector(yourRefreshMethod:) forControlEvents:UIControlEventValueChanged];

Você pode pensar que está procurando o seletor:

- (void)yourRefreshMethod{
    (your code here)
}

Mas, na verdade, está procurando o seletor:

- (void)yourRefreshMethod:(id)sender{
    (your code here)
}

Esse seletor não existe, então você obtém a falha.

Você pode alterar o seletor para receber o remetente (id) para resolver o erro.

Mas e se você tiver outras funções que chamam a função de atualização sem fornecer um remetente? Você precisa de uma função que funcione para ambos. A solução fácil é adicionar outra função:

- (void)yourRefreshMethodWithSender:(id)sender{
    [self yourRefreshMethod];
}

E modifique o código de atualização para chamar esse seletor:

[self.refreshControl addTarget:self action:@selector(yourRefreshMethodWithSender:) forControlEvents:UIControlEventValueChanged];

Também estou fazendo o curso Stanford iOS em um Mac antigo que não pode ser atualizado para a versão mais recente do Mac OSX. Ainda estou construindo para o iOS 6.1, e isso resolveu o problema para mim.

Joseph Pride
fonte
2

No meu caso, resolvi o problema após 2 horas:

O remetente (um item tabBar) não estava tendo nenhuma saída de referência . Então não estava apontando para lugar nenhum.

Juste criar uma tomada de referência correspondente à sua função.

Espero que isso possa ajudar vocês.

André DS
fonte
Só para acrescentar, no meu caso eu esqueci de portar um IBActionpara o Swift. Por isso, estava reclamando que queria chamar essa função, mas não pôde ser encontrada.
DevNebulae 21/01
1

Atualmente, estou aprendendo o desenvolvimento do iOS e lendo o livro "Beginning iOS6 Development" da aPress. Eu estava recebendo o mesmo erro no Capítulo 10: Storyboards.

Levei dois dias para descobrir, mas descobri que acidentalmente defino a tag da célula do TableView como 1 quando não deveria. Para qualquer pessoa que faça este livro e receba um erro semelhante, espero que isso ajude.

Eu realmente espero que erros futuros no meu código sejam mais fáceis de encontrar! hahaha. O erro de depuração não fez nada para me levar na direção certa para descobrir isso (ou pelo menos eu sou novo demais para entender o depurador, risos).

Shannon Cole
fonte
1

No meu caso, eu estava usando um UIWebView e passei um NSString no segundo parâmetro em vez de um NSURL. Portanto, suspeito que tipos de classe incorretos passados ​​para uma função podem causar esse erro.

jbaylina
fonte
1

..E agora meu

Eu tinha o botão vinculado a um método que acessava o parâmetro de outro botão e funcionou muito bem, mas assim que tentei fazer algo com o próprio botão, tive um acidente. Durante a compilação, nenhum erro foi exibido. Solução?

Falha ao vincular o botão ao proprietário do arquivo. Então, se alguém aqui é tão estúpido quanto eu, tente isso :)

user2875404
fonte
1

Mais uma solução / caso ligeiramente diferente.

Estou usando o Xamarin e o MvvmCross e estava tentando vincular o UIButton a um ViewModel. Eu tinha o UIButton conectado a uma tomada e um TouchUpInside.

Ao Encadernar, só uso o Outlet:

set.Bind (somethingOutlet).For ("TouchUpInside").To(vm => vm.Something);

Tudo o que eu precisava fazer era remover a conexão de ação (TouchUpInside) no XCode e isso foi resolvido.

PS Eu acho que isso está em sua base, tudo relacionado às respostas anteriores e a @ Chris Kaminski em particular, mas espero que isso ajude alguém ...

Felicidades.

YKa
fonte
1

Eu tive o mesmo problema. O problema para mim era que um botão tinha dois métodos de ação. O que fiz foi criar um primeiro método de ação para o meu botão e excluí-lo no controlador de exibição, mas esqueci de desconectar a conexão no storyboard principal no inspetor de conexões. Então, quando adicionei um segundo método de ação, havia agora dois métodos de ação para um botão, o que causou o erro.

Harshil.Chokshi
fonte
1

Para mim, era uma conexão restante criada no interfacebuilder com o arrastamento do ctrl. O nome da conexão interrompida estava no log de erros

*** Terminating app due to uncaught exception 'NSInvalidArgumentException',
reason: '-[NameOfYourApp.NameOfYourClass nameOfCorruptConnection:]:
unrecognized selector sent to instance 0x7f97a48bb000'

Eu tive uma ação vinculada a um botão. Pressionar o botão travou o aplicativo porque o Outlet não existia mais no meu código. Procurar o nome no log me levou a ele no storyboard. Excluiu e o acidente desapareceu!

Tom Brinkkemper
fonte
0

Estou respondendo a Leonard Challis, já que também estava na classe C193P do iOS de Stanford, assim como o usuário "oli206"

"Finalizando o aplicativo devido à exceção não capturada 'NSInvalidArgumentException', motivo:"

O problema era que eu tinha o botão "Enter" na calculadora conectado duas vezes, e um amigo apontou que, ao inspecionar o botão no Storyboard, havia duas entradas nos atributos "Touch Up Inside" ao clicar com o botão direito do mouse. o botão "Enter". A exclusão de um dos dois "Touch Up Inside" "Send Events" resolveu o problema.

Isso mostrou que o problema é acionado (para a classe de vídeo C193P no passo a passo da calculadora na atribuição 1) como dois eventos enviados, um dos quais estava causando a exceção.

Peter_from_NYC
fonte
Eu tinha 3 entradas de alguma forma. :)
1,21 gigawatts 05/03
0

Isso pode acontecer quando você não atribui o ViewController ao ViewControllerScene no InterfaceBuilder. Portanto, o ViewController.m não está conectado a nenhuma cena.

Vincent
fonte
0

Incluindo minha parte. Fiquei preso por um tempo, até perceber que havia criado um projeto com o ARC (referência de contagem automática) desativado. Uma configuração rápida para SIM nessa opção resolveu meu problema.

caiocpricci2
fonte
0

Outra causa realmente tola disso é ter o seletor definido na interface (.h), mas não na implementação (.m) (erro de digitação pe)

jla
fonte
0

Outro motivo / solução para adicionar à lista. Este é causado pelo iOS6.0 (e / ou programação incorreta). Nas versões anteriores, o seletor corresponderia se os tipos de parâmetro correspondessem, mas no iOS 6.0 eu ocorria falhas no código que trabalhava anteriormente, onde o nome do parâmetro não estava correto.

Eu estava fazendo algo como

[objectName methodName:@"somestring" lat:latValue lng:lngValue];

mas na definição (.hem .m) eu tinha

(viod) methodName:(NSString *) latitude:(double)latitude longitude:(double)longitude;

Isso funcionou bem no iOS5, mas não no 6, mesmo a mesma compilação implantada em diferentes dispositivos.

Eu não entendo por que o compilador não pode me dizer isso, de qualquer maneira - solução do problema.

Tim T
fonte
0

Isso também pode acontecer quando você deseja definir uma propriedade de um ControllerA para uma propriedade pública dentro de uma classe ControllerB personalizada e ainda não definiu a "Classe Personalizada" dentro do inspetor de identidade nos storyboards.

Francisco Gutiérrez
fonte
0

Meu problema e solução eram diferentes e achei que deveria publicá-lo aqui para que futuros leitores possam salvar sua cabeça de bater na parede.

Eu estava alocando xib diferente no mesmo UIVIewController e, mesmo depois de pesquisar em todos os lugares, não consegui encontrar como corrigi-lo. Depois, verifiquei meu AppDelegate para onde estava ligando initWithNibNamee posso ver que, ao copiar o código, mudei o nome do xib, mas esqueci de mudar de UIViewControllerclasse. Portanto, se nenhuma solução funcionar para você, verifique seu initWithNibNamemétodo.

novato
fonte
0

Aconteceu comigo por causa de argumentos de restrição conflitantes.

Alex Bedro
fonte