web-dev-qa-db-fra.com

erreur "sélecteur non reconnu envoyé à l'instance" dans Objective-C

J'ai créé un bouton et ajouté une action pour cela, mais dès qu'il l'a invoqué, j'ai eu cette erreur:

-[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'

Ceci est mon code:

- (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(@"---");
}
141
HelloWorld

Il semble que vous ne gérez pas correctement le contrôleur de vue en mémoire et qu'il est désalloué à un moment donné, ce qui entraîne l'envoi de la méthode numberButtonClicked: à un autre objet occupant maintenant la mémoire occupée précédemment par le contrôleur de vue ...

Assurez-vous de bien conserver/libérer votre contrôleur de vue.

176
Jasarien

Pour ceux qui arrivent via Google comme moi, ce qui est probablement plus lié à Xcode 4.2 +/iOS 5+, qu’à ARC. J'ai eu la même erreur " sélecteur non reconnu envoyé à instance ". Dans mon cas, une action cible d'UIButton avait été configurée pour passer elle-même en tant que paramètre sender, mais j'ai réalisé plus tard que je n'en avais pas besoin et je l'ai supprimée dans le code. Donc, quelque chose comme:

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

A été changé en:

- (IBAction)buttonPressed {

Un clic droit sur le bouton UIB en question a montré que l'événement Touch Up Inside était associé à la méthode buttonPressed: de la vue Contrôleurs. Enlever cela et le réaffecter à la méthode modifiée a fonctionné.

123
LeonardChallis

C’était la meilleure réponse de Google à ce problème, mais j’avais une cause/un résultat différent - j’avais pensé ajouter plus de deux centimes au cas où d’autres tomberaient sur ce problème. 

J'ai eu un problème similaire juste ce matin. J'ai constaté que si vous faites un clic droit sur l'élément de l'interface utilisateur qui vous donne le problème, vous pouvez voir quelles connexions ont été créées. Dans mon cas, j'avais un bouton connecté à deux actions. J'ai supprimé les actions du menu contextuel et les ai recâblées et mon problème a été résolu.

Donc, assurez-vous que vos actions sont correctement connectées.

68
Chris K

OK, je dois participer ici. L'OP a créé dynamiquement le bouton . J'ai eu un problème similaire et la réponse (après des heures de chasse) est si simple qu'elle m'a rendu malade.

En utilisant:

action:@selector(xxxButtonClick:)

or (as in my case)

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

Si vous placez un point deux-points à la fin de la chaîne, l'expéditeur sera transmis. Si vous ne placez pas les deux points à la fin de la chaîne, ce ne sera pas le cas, et le destinataire obtiendra une erreur s'il en attend une. Il est facile de rater les deux points si vous créez de manière dynamique le nom de l'événement.

Les options du code du destinataire ressemblent à ceci:

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

Comme d'habitude, c'est toujours la réponse évidente qui nous manque.

24
Craig H.

Dans mon cas, la fonction n'attendait pas d'argument, mais le bouton était configuré pour envoyer un argument à l'origine de l'erreur. Pour résoudre ce problème, j'ai dû recâbler le gestionnaire d'événements. 

Voici ma fonction: 

enter image description here

Notez qu'il ne contient aucun argument. 

Voici une image de la configuration de mon bouton (clic droit sur le bouton pour l'afficher): 

enter image description here

Notez qu'il y a 3 gestionnaires d'événements. 

Pour résoudre ce problème, j'ai dû supprimer chacun des éléments de l'événement, car l'un d'entre eux envoyait une référence à lui-même à la fonction enterPressed. Pour supprimer ces éléments, j'ai cliqué sur la petite icône x en regard du nom de chaque élément jusqu'à ce qu'aucun élément ne soit affiché. 

enter image description here

Ensuite, j'ai dû reconnecter le bouton à l'événement. Pour ce faire, maintenez la touche Ctrl enfoncée, puis faites glisser une ligne du bouton vers l'action. Il devrait dire "Connect Action". Remarque: je devais redémarrer XCode pour que cela fonctionne pour une raison quelconque; sinon, il me laisse seulement insérer des actions (créer une nouvelle action) au-dessus ou au-dessous de la fonction. 

enter image description here

Vous devriez maintenant avoir un seul gestionnaire d’événements connecté à l’événement button qui ne transmet aucun argument: 

enter image description here

Cette réponse complète la réponse de @Lonard Challis que vous devriez également lire. 

22
1.21 gigawatts

Cela peut également se produire si vous ne définissez pas la "Classe" de la vue dans le générateur d'interface.

14
user1658373

Dans mon cas, j'utilisais NSNotificationCenter et j'essayais d'utiliser un sélecteur qui ne prenait aucun argument, mais qui ajoutait deux points. Supprimer les deux points a résolu le problème.

Lorsque vous utilisez un nom de sélecteur, n'utilisez pas de deux-points de fin s'il n'y a pas d'argument. S'il y a un argument, utilisez un point de fuite. S'il y a plus d'un argument, vous devez les nommer avec un deux-points final pour chaque argument.

Voir la réponse d'Adam Rosenfield ici: Les sélecteurs dans Objective C

12
Nathan Garabedian

J'ai eu ce problème avec un projet Swift où je crée les boutons dynamiquement. Code du problème:

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).")
}

La solution consistait à ajouter un point-virgule complet ':' après l'action.

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).")
    }

Exemple complet ici: https://developer.Apple.com/library/content/samplecode/UICatalog/Listings/Swift_UIKitCatalog_DefaultToolbarViewController_Swift.html

11
FredL

La cause la plus évidente de ceci (inclus pour des raisons d'exhaustivité) consiste à mal positionner un pointeur et à appeler une méthode de la mauvaise classe.

NSArray* array = [[NSArray alloc] init];
[(NSDictionary*)array objectForKey: key]; // array is not a dictionary, hence exception
5
devios1

J'ai eu la même erreur et j'ai découvert ce qui suit:

Quand vous utilisez le code

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

Vous pensez peut-être qu'il recherche le sélecteur:

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

Mais c'est en fait la recherche du sélecteur:

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

Ce sélecteur n'existe pas, vous obtenez donc le crash.

Vous pouvez modifier le sélecteur pour recevoir l'expéditeur (id) afin de résoudre l'erreur.

Mais que se passe-t-il si d'autres fonctions appellent la fonction d'actualisation sans fournissant un expéditeur? Vous avez besoin d'une fonction qui fonctionne pour les deux. La solution facile consiste à ajouter une autre fonction:

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

Et puis modifiez le code déroulant d'actualisation pour appeler ce sélecteur à la place:

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

Je suis également le cours iOS de Stanford sur un ancien Mac qui ne peut pas être mis à niveau vers la dernière version de Mac OSX. Donc, je suis toujours en train de construire pour iOS 6.1, et cela résout le problème pour moi.

3
Joseph Pride

J'ai aussi eu le même problème.

J'ai supprimé mon uibutton dans mon storyboard et je l'ai recréé. 

3
Yohan Dahmani

J'ai eu un problème similaire, mais pour moi la solution était légèrement différente. Dans mon cas, j'ai utilisé une catégorie pour étendre une classe existante (UIImage pour certaines capacités de redimensionnement - voir ce howto si cela vous intéresse) et j'ai oublié d'ajouter le fichier * .m à la cible de construction. Erreur stupide, mais pas toujours évidente quand il arrive où chercher. Je pensais que ça valait la peine de partager ...

3
Mirko Jahn

Je pense que vous devriez utiliser le vide, au lieu de IBAction dans le type de retour. parce que vous avez défini un bouton par programmation. 

2
Fa.Shapouri

Cela m'est arrivé parce que j'avais accidentellement effacé "@IBAction func ..." dans le code de la classe UIViewcontroller. Ainsi, dans le Storyboard, la prise de référence avait été créée, mais il n'existait aucune fonction permettant de le traiter. 

La solution consistait à supprimer la référence Prise dans l'inspecteur de propriétés, puis à la recréer en la faisant glisser avec la touche de commande dans le code de la classe.

J'espère que ça aide!

2
Guillermo

J'ai eu le même problème. Le problème pour moi était qu'un bouton avait deux méthodes d'action. Ce que j'ai fait est de créer une première méthode d'action pour mon bouton, puis de la supprimer dans le contrôleur de vue, mais j'ai oublié de déconnecter la connexion dans le scénario principal dans l'inspecteur de connexion. Ainsi, lorsque j’ai ajouté une deuxième méthode d’action, il existait maintenant deux méthodes d’action pour un bouton, ce qui était à l’origine de l’erreur. 

1
Harshil.Chokshi

Encore une autre solution légèrement différente. 

J'utilise Xamarin et MvvmCross et j'essayais de lier l'UIButton à un ViewModel. J'ai fait brancher l'UIButton à une prise et à un TouchUpInside.

Lorsque je lie, je n'utilise que la prise:

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

Tout ce que je devais faire était de supprimer la connexion d'action (TouchUpInside) dans XCode et cela la résolvait. 

P.S . Je suppose que cela se trouve dans sa base, tous liés aux réponses précédentes et à @Chris Kaminski en particulier, mais j'espère que cela aidera quelqu'un ...

À votre santé. 

1
YKa

Et maintenant le mien

J'avais le bouton lié à une méthode qui permettait d'accéder à un paramètre d'un autre bouton et cela fonctionnait bien MAIS dès que j'ai essayé de faire quelque chose avec le bouton lui-même, j'ai eu un crash. Lors de la compilation, aucune erreur n’a été affichée. Solution?

J'ai échoué à lier le bouton au propriétaire du fichier. Donc, si quelqu'un ici est aussi stupide que moi, essayez ceci :)

1
user2875404

Dans mon cas, j'utilisais UIWebView et j'ai passé un NSString dans le deuxième paramètre au lieu d'un NSURL. Donc, je soupçonne que les mauvais types de classe passés à une fonction peuvent être à l'origine de cette erreur. 

1
jbaylina

J'apprends actuellement le développement iOS et je lis le livre "Début du développement iOS6" de aPress. La même erreur se produisait au chapitre 10: Storyboards.

Il m'a fallu deux jours pour le comprendre, mais j'ai découvert que j'avais accidentellement réglé le tag de la cellule TableView sur 1 alors que je n'aurais pas dû. Pour tous ceux qui font ce livre et reçoivent une erreur similaire, j'espère que cela aidera. 

J'espère vraiment que les futures erreurs dans mon code seront plus faciles à trouver! hahaha. L’erreur de débogage ne m’a pas poussé dans la bonne direction (ou du moins je suis trop nouveau pour comprendre le débogueur, lol).

1
Shannon Cole

Sur mon cas, j'ai résolu le problème après 2 heures:

L'expéditeur (un élément TabBar) ne disposait d'aucune prise de référencement Donc, il ne pointait nulle part.

Juste créer une prise de référencement correspondant à votre fonction.

J'espère que cela pourrait vous aider les gars.

1
André DS

Pour moi, c’était une connexion restante créée dans interfacebuilder par ctrl-glisser. Le nom de la connexion interrompue était dans le journal des erreurs

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

J'ai eu une action liée à un bouton. L'appui sur le bouton a bloqué l'application parce que la prise de courant n'existait plus dans mon code… .. La recherche du nom dans le journal m'a conduit à cette information dans le storyboard. Supprimé, et le crash était parti!

1
Tom Brinkkemper

Une autre cause vraiment stupide de cela est d'avoir le sélecteur défini dans l'interface (.h) mais pas dans l'implémentation (.m) (p.

0
jla

Je réponds à Leonard Challis, étant donné que je prenais également la classe iOS de Stanford C193P, tout comme l'utilisateur "oli206".

"Application interrompue en raison d'une exception non interceptée 'NSInvalidArgumentException', raison:"

Le problème était que le bouton "Entrer" de la calculatrice était connecté deux fois, et un ami a fait remarquer que l'inspection du bouton dans le Storyboard avait montré que 2 entrées étaient associées aux attributs "Retouche à l'intérieur" lorsque j'ai cliqué avec le bouton droit. le bouton "Enter". L’effacement de l’un des deux "Retouches à l’intérieur" "Evénements envoyés" a résolu le problème.

Cela montrait que le problème était déclenché (pour la classe vidéo C193P sur la procédure pas à pas de la calculatrice sur l'affectation 1) en tant que 2 événements envoyés, dont l'un était à l'origine de l'exception.

0
Peter_from_NYC

Je l’ai eu après avoir basculé de Swift 2 à Swift 3. La description ci-dessous est spécifique, mais vous pouvez voir que le cas générique de celui-ci couvre un grand nombre d’erreurs possibles.

J'avais une méthode appelée delete dans ma sous-classe de SKNode

func delete(thing: SomeType) 

Il existe déjà une méthode delete sur UIResponder, mais ma méthode l'a surchargée (involontairement), donc elle fonctionnait bien. La mise à niveau vers Swift 3 l'a modifié en:

func delete(_ thing: SomeType) 

Je travaille encore. Mais alors j'ai décidé de Swift3ify et de rendre le paramètre obligatoire:

func delete(thing: SomeType)

ce qui aurait très bien fonctionné si je m'étais souvenu de mettre à jour l'appelant, mais je ne l'ai pas fait maintenant. l'appelant appelle la méthode no-paramètre-nom delete dans UIResponder avec le type d'argument incorrect.

Cela peut évidemment se produire avec l’une des nombreuses méthodes standard de SKNode (et probablement UIView) qui prend Any comme argument et passera donc la phase de compilation mais sera ensuite basculé lorsqu’il sera appelé.

0
rghome

Mon cas était: collectionView inside a View

J'essayais d'ajouter le gestureRecognizer dans une méthode config() que j'avais écrite moi-même… .. Après une solution de contournement, j'ai trouvé que Je dois simplement déplacer le code dans la awakeFromNib().

override func awakeFromNib() {

   //other code

   let longPressGesture = UILongPressGestureRecognizer(target: self, action: #selector(handleLongGesture(gesture:)))
   self.collectionView.addGestureRecognizer(longPressGesture)
}

Et ça a bien fonctionné.

J'espère que cela peut aider quelqu'un.

0
Federico Arvat

Une autre raison/solution à ajouter à la liste. Celui-ci est causé par iOS6.0 (et/ou une mauvaise programmation). Dans les anciennes versions, le sélecteur correspondait si les types de paramètres correspondaient, mais sous iOS 6.0, le code fonctionnait auparavant et le nom du paramètre n'était pas correct.

Je faisais quelque chose comme 

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

mais dans la définition (.h et .m) j'avais

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

Cela a bien fonctionné sur iOS5 mais pas sur 6, même la même version exacte déployée sur différents appareils.

Je ne comprends pas pourquoi le compilateur ne m'a pas dit ça, de toute façon - le problème est résolu.

0
Tim T

Mon problème et ma solution étaient différents et je pensais que je devrais le poster ici afin que les futurs lecteurs puissent éviter de se cogner au mur. 

J'attribuais différents fichiers xib au même UIVIewController et même après avoir cherché partout, je ne trouvais pas comment le corriger. Ensuite, j'ai vérifié mon AppDelegate où j'appelais initWithNibName et je peux voir que lors de la copie du code, j'ai changé le nom de xib, mais j'ai oublié de changer la classe UIViewController. Donc, si aucune des solutions ne fonctionne pour vous, vérifiez votre méthode initWithNibName.

0
noob

Y compris ma part. Je suis resté coincé là-dessus pendant un moment, jusqu'à ce que je réalise que j'ai créé un projet avec ARC (référence de comptage automatique) disabled. Un réglage rapide sur OUI pour cette option a résolu mon problème.

0
caiocpricci2

Cela peut arriver lorsque vous n'affectez pas ViewController à ViewControllerScene dans InterfaceBuilder. Donc, ViewController.m n'est connecté à aucune scène.

0
Vincent

Dans mon cas: 

Ma définition de protocole 

 @protocol MyProtocol

- (void)Method;

@end

et j'ai oublié implémente les méthodes déléguées.

j'espère que cela pourrait aider quelqu'un. 

0
liu jeff

J'ai eu ce problème en essayant un ancien code de format dans Swift3

let swipeRight = UISwipeGestureRecognizer(target: self, action: #selector(self.respond))

changer le action:"respond:" en action: #selector(self.respond) a corrigé le problème pour moi.

0
sabithpocker

Cela peut également arriver lorsque vous souhaitez définir une propriété d'un ControllerA sur une propriété publique dans une classe ControllerB personnalisée et que vous n'avez pas encore défini la "Classe personnalisée" dans l'inspecteur d'identité dans les storyboards.

0

Notions de base: Invocation dynamique

Objective C est un langage dynamique qui appelle des méthodes en examinant les méthodes d'exécution dans les classes à l'exécution. Par exemple, s'il existe Classe A Méthode include DoSomething (arg1, arg2) . Si vous essayez d'appeler la méthode en utilisant les arguments corrects sur un objet de Classe A tout fonctionnera correctement. Toutefois, si les arguments ne sont pas correctement passés, par exemple, si vous avez appelé la méthode avec un seul argument, l'exécution le traitera comme un appel à une méthode différente. Finalement, l'exécution ne trouvera pas la méthode (DoSomething avec un argument) et traversera cette exception "le sélecteur non reconnu envoyé à l'instance"

Solution

Veuillez vérifier quelle signature for @selector est attendue. Comme d'habitude, comme vous l'avez décrit dans le code

-(IBAction)numberButtonClick:(id)sender{
0
hadaytullah

Une autre solution possible: Ajoutez '-ObjC' à vos arguments d'éditeur de liens.

Les explications complètes se trouvent ici: Catégories Objective-C dans une bibliothèque statique

Je pense que le résumé est le suivant: si la catégorie est définie dans une bibliothèque avec laquelle vous créez un lien statique, l'éditeur de liens n'est pas assez intelligent pour lier des méthodes de catégorie. Le drapeau ci-dessus crée un lien dans l’éditeur de liens dans toutes les classes et catégories d’objectif C, et pas seulement pour celles qu’il pense qu’il doit fonder sur une analyse de votre source. (S'il vous plaît, n'hésitez pas à accorder ou à corriger cette réponse. Je suis connu pour les langues liées, donc je ne fais que copier ici).

0
Russ Egan

Cela m'est arrivé à cause d'arguments de contrainte contradictoires.

0
Alex Bedro

J'ai aussi eu le problème et j'ai enfin trouvé la solution à mon problème. J'ai construit le controller'sUI dans le storyboard, mais le controller'sUI ne faisait pas correspondre son contrôle au code. J'utilise ce code pour init vc:

    UIStoryboard *sb = [UIStoryboard storyboardWithName:@"Me" bundle:nil];
    [sb instantiateViewControllerWithIdentifier:@"HeaderViewController"];

Ce code ci-dessus va causer le problème, et après avoir changé le code init en celui-ci, j'ai résolu le problème:

HeaderViewController *head_vc = [[HeaderViewController alloc] init];
0
aircraft