Erreur "Sélecteur non reconnu envoyé à l'instance" dans Objective-C

155

J'ai créé un bouton et ajouté une action pour celui-ci, mais dès qu'il s'est appelé, 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'

Voici 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(@"---");
}
Bonjour le monde
la source

Réponses:

187

Il semble que la mémoire ne gère pas correctement le contrôleur de vue et qu'il est en cours de désallocation à un moment donné - ce qui entraîne l' numberButtonClicked:envoi de la méthode à un autre objet qui occupe maintenant la mémoire que le contrôleur de vue occupait auparavant ...

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

Jasarien
la source
105
C'est un diagnostic très astucieux à partir de très peu de lignes de code.
Michael Morrison
41
OK, donc problème identifié ... mais "Assurez-vous que vous conservez / libérez correctement votre contrôleur de vue." est une suggestion, pas une solution.
Alex Gray le
12
@alex gray, quoi? Une bonne gestion de la mémoire sur le contrôleur de vue a résolu le problème ... Je ne comprends pas en quoi ce n'est pas une solution?
Jasarien le
28
correct. bien que cela semble être "le correctif" .. et je peux être dans la minorité, (bien que j'arrive toujours à exister), mais le lien entre le problème et la solution n'est pas immédiatement évident. par exemple, je rencontre -[NSWindow end]: unrecognized selector sent to instance 0x100523e80 et bien que je réalise les similitudes avec l'OP, et même peut-être la cause du problème de votre réponse, la mise en œuvre d'un correctif n'est pas immédiatement évidente
Alex Gray
12
C'est immédiatement évident. Votre gestion de la mémoire NSWindow n'est pas correcte quelque part sur la ligne. Passez par son cycle de vie et corrigez-le.
Jasarien
127

Pour ceux qui arrivent ici via Google comme je l'ai fait, ce qui concerne probablement plus Xcode 4.2 + / iOS 5+ plus, qu'avec ARC. J'ai eu la même erreur " Sélecteur non reconnu envoyé à l'instance ". Dans mon cas, une action cible d'UIButton avait été configurée pour se passer comme paramètre d'expéditeur, 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 l'UIButton en question a montré que l'événement Retouche à l'intérieur était associé à la méthode ButtonPressed: des contrôleurs de vue. Le supprimer et le réaffecter à la méthode modifiée a fonctionné un régal.

LeonardChallis
la source
Cela a été très utile, même si je pense que sa propre question et réponse faciliteraient sa recherche.
Curtis Inderwiesche
@LeonardChallis Comment pouvez-vous référencer l'expéditeur dans buttonPressed s'il n'est pas passé en paramètre?
zakdances
8
Réponse très utile. Je viens de rencontrer ce problème exact et votre solution était exactement la bonne. A suivi le cours iOS de Stanford sur iTunesU lorsque cela s'est produit. Merci encore pour votre réponse!
Marshall Alsup
1
@LeonardChallis Merci. J'ai ajouté une réponse complémentaire à votre réponse.
1,21 gigawatts
1
J'étais juste aux prises avec un problème similaire, j'ai supprimé le paramètre sender de la fonction de sélection, puis je me suis demandé comment obtenir l'expéditeur. Dans mon cas, j'obtenais l'erreur parce que j'avais oublié de mettre un deux-points après le rappel du sélecteur, provoquant ainsi une incompatibilité de séquence d'appel. Avec les deux points, je peux conserver l'argument de l'expéditeur.
74

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

J'ai eu un problème similaire ce matin. J'ai constaté que si vous cliquez avec le bouton droit sur l'élément d'interface utilisateur qui vous pose le problème, vous pouvez voir quelles connexions ont été créées. Dans mon cas, j'avais un bouton câblé jusqu'à deux actions. J'ai supprimé les actions du menu contextuel et les ai reconnectées et mon problème a été résolu.

Assurez-vous donc que vos actions sont correctement câblées.

Chris K
la source
C'était mon problème. J'ai renommé une fonction et changé mon code mais je n'ai pas changé la connexion dans le fichier xib.
BFTrick
2
MERCI! Il s'est avéré que j'avais trois méthodes que j'avais supprimées encore référencées. Ça me dérange pendant une semaine!
erdekhayser
25

OK, je dois participer ici. L'OP a créé le bouton de manière dynamique . 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.

Lors de l'utilisation:

action:@selector(xxxButtonClick:)

or (as in my case)

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

Si vous placez un signe deux-points à la fin de la chaîne, il passera l'expéditeur. Si vous ne placez pas les deux points à la fin de la chaîne, ce ne sera pas le cas et le récepteur recevra une erreur s'il en attend une. Il est facile de rater les deux points si vous créez dynamiquement le nom de l'événement.

Les options de code du récepteur 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 est manquée.

Craig H.
la source
1
Merci beaucoup! C'était mon problème (ne pas mettre de deux points ':' à la fin du nom du sélecteur). Comment se fait-il que ce soient presque toujours les choses simples les plus stupides qui nous font cogner la tête contre le mur à 3 heures du matin? Vraiment merci!
TWright
23

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

Voici ma fonction:

entrez la description de l'image ici

Notez qu'il ne contient aucun argument.

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

entrez la description de l'image ici

Notez qu'il existe 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'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 à côté du nom de chaque élément jusqu'à ce qu'il n'y ait plus d'éléments affichés.

entrez la description de l'image ici

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

entrez la description de l'image ici

Vous devriez maintenant avoir un seul gestionnaire d'événements câblé à l'événement de bouton qui ne transmet aucun argument:

entrez la description de l'image ici

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

1,21 gigawatts
la source
14

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

user1658373
la source
Agh merci! Cela provoquait le crash de mon application sur une séquence, j'ai simplement oublié de définir la classe du contrôleur.
Eichhörnchen
Pourquoi a-t-il besoin de connaître la classe? J'essaye d'utiliser un UITableViewSection comme un UIView, et j'obtiens donc cette erreur. Le compilateur dit que UITableViewSection n'existe pas donc je présume qu'il est interne à UIKit.
Ian Warburton
13

Dans mon cas, j'utilisais NSNotificationCenter et j'essayais d'utiliser un sélecteur qui ne prenait aucun argument, mais ajoutait un deux-points. La suppression des 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'arguments. S'il y a un argument, utilisez un deux-points à la fin. S'il y a plus d'un argument, vous devez les nommer avec un deux-points pour chaque argument.

Voir la réponse d'Adam Rosenfield ici: Sélecteurs en Objective-C?

Nathan Garabedian
la source
11

J'ai eu ce problème avec un projet Swift où je crée les boutons de manière dynamique. 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 était d'ajouter un deux-points ':' après l'action: par exemple

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

FredL
la source
Juste après avoir suivi le tutoriel et lu un indice sur exactement le même problème - je suis tombé sous le
charme
6

La cause la plus évidente de ceci (incluse par souci d'exhaustivité) est la conversion incorrecte d'un pointeur et l'appel d'une méthode de la mauvaise classe.

NSArray* array = [[NSArray alloc] init];
[(NSDictionary*)array objectForKey: key]; // array is not a dictionary, hence exception
devios1
la source
C'est un bon indice - ne pas sous-classer une vue ou un objet de données (par exemple en échouant à ajouter un nom de sous-classe) est une autre façon de procéder
Brad M
4

J'ai également eu le même problème.

J'ai supprimé mon uibutton dans mon storyboard et l'ai recréé .. maintenant tout fonctionne bien.

Yohan Dahmani
la source
3

J'avais 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 fonctionnalités de redimensionnement - voir ce guide au cas où vous seriez intéressé) et j'ai oublié d'ajouter le fichier * .m à la cible de construction. Erreur stupide, mais pas toujours évidente quand il se passe où chercher. J'ai pensé que ça valait le coup d'être partagé ...

Mirko Jahn
la source
3

Cela m'est arrivé parce que j'ai accidentellement effacé le "@IBAction func ..." à l'intérieur de mon code de classe UIViewcontroller, donc dans le Storyboard a été créé la sortie de référence, mais au moment de l'exécution, il y avait une fonction pour le traiter.

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

J'espère que ça aide!

Guillermo
la source
De même, cela m'est également arrivé lorsque le bouton faisait référence à une fonction qui n'existait plus.
Josh Wolff
2

Je pense que vous devriez utiliser le void, au lieu de l'IBAction en type de retour. car vous avez défini un bouton par programmation.

Fa.Shapouri
la source
2

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

L'explication complète est ici: Catégories Objective-C dans la bibliothèque statique

Je pense que l'essentiel est: 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 créer des liens dans les méthodes de catégorie. L'indicateur ci-dessus crée le lien de l'éditeur de liens dans toutes les classes et catégories objectives C, pas seulement celles dont il pense avoir besoin en fonction de l'analyse de votre source. (S'il vous plaît n'hésitez pas à régler ou corriger cette réponse. Je connais les langues liées, donc je ne fais que perroquet ici).

Russ Egan
la source
2

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

Lorsque vous utilisez le code

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

Vous pensez peut-être qu'il cherche 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, donc vous obtenez le crash.

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

Mais que faire si vous avez d'autres fonctions qui appellent la fonction d'actualisation sans fournir d'expéditeur? Vous avez besoin d'une fonction qui fonctionne pour les deux. La solution simple 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 en train de suivre le cours Stanford iOS sur un ancien Mac qui ne peut pas être mis à niveau vers la dernière version de Mac OSX. Je suis donc toujours en train de construire pour iOS 6.1, et cela a résolu le problème pour moi.

Joseph Pride
la source
2

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

L'expéditeur (un élément tabBar) n'avait pas de sortie de référencement . Donc ça ne pointait nulle part.

Créez simplement une prise de référencement correspondant à votre fonction.

J'espère que cela pourrait vous aider.

André DS
la source
Juste pour ajouter, dans mon cas, j'ai oublié de porter un IBActionvers Swift. Donc, il se plaignait de vouloir appeler cette fonction, mais il n'a pas pu être trouvé.
DevNebulae
1

J'apprends actuellement le développement iOS et je suis en train de parcourir le livre "Beginning iOS6 Development" par aPress. J'obtenais la même erreur dans le chapitre 10: Storyboards.

Il m'a fallu deux jours pour le comprendre, mais j'ai découvert que j'avais accidentellement défini la balise 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 aide.

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

Shannon Cole
la source
1

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

jbaylina
la source
1

.. et maintenant le mien

J'avais le bouton lié à une méthode qui accédait au paramètre d'un autre bouton et qui fonctionnait très 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?

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

user2875404
la source
1

Encore une autre solution / cas légèrement différent.

J'utilise Xamarin et MvvmCross et j'essayais de lier l'UIButton à un ViewModel. J'ai eu l'UIButton câblé à un Outlet et un TouchUpInside.

Lors de la liaison, j'utilise uniquement la prise:

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

Tout ce que j'avais à faire était de supprimer la connexion d'action (TouchUpInside) dans XCode et cela l'a résolu.

PS Je suppose que c'est dans sa base que tout est lié aux réponses précédentes et à @Chris Kaminski en particulier, mais j'espère que cela aide quelqu'un ...

À votre santé.

YKa
la source
1

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 a été 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 storyboard principal dans l'inspecteur de connexion. Ainsi, lorsque j'ai ajouté une deuxième méthode d'action, il y avait maintenant deux méthodes d'action pour un bouton, ce qui a causé l'erreur.

Harshil.Chokshi
la source
1

Pour moi, c'était une connexion restante créée dans interfacebuilder par ctrl-dragging. 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. En appuyant sur le bouton, l'application a planté car la prise n'existait plus dans mon code. La recherche du nom dans le journal m'a conduit à celui-ci dans le storyboard. Supprimé, et le crash a disparu!

Tom Brinkkemper
la source
0

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

"Arrêt de l'application en raison d'une exception non interceptée 'NSInvalidArgumentException', raison:"

Le problème était que j'avais le bouton "Entrer" sur la calculatrice connecté deux fois, et un ami a souligné que faire une inspection du bouton dans le Storyboard a montré que 2 entrées étaient sur les attributs "Retouche à l'intérieur" lorsque j'ai cliqué avec le bouton droit sur le bouton "Entrée". L'effacement de l'un des deux événements envoyés "Retouche à l'intérieur" a résolu le problème.

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

Peter_from_NYC
la source
J'ai eu 3 entrées quelque peu. :)
1,21 gigawatts
0

Cela peut se produire lorsque vous n'affectez pas le ViewController à ViewControllerScene dans InterfaceBuilder. Ainsi, le ViewController.m n'est connecté à aucune scène.

Vincent
la source
0

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 (Automatic counting reference) désactivé. Un réglage rapide sur OUI sur cette option a résolu mon problème.

caiocpricci2
la source
0

Une autre cause vraiment idiote de ceci est d'avoir le sélecteur défini dans l'interface (.h) mais pas dans l'implémentation (.m) (faute de frappe)

jla
la source
0

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 correspondrait si les types de paramètres correspondaient, mais dans iOS 6.0, j'ai eu des plantages dans un code précédemment fonctionnel où 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 (à la fois .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 déployée sur différents appareils.

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

Tim T
la source
0

Cela peut également se produire lorsque vous souhaitez définir une propriété d'un ControllerA vers 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.

Francisco Gutiérrez
la source
0

Mon problème et ma solution étaient différents et j'ai pensé que je devrais le poster ici pour que les futurs lecteurs puissent éviter de se cogner la tête contre le mur.

J'allouais différents xib au même UIVIewController et même après avoir cherché partout, je ne pouvais pas trouver comment le corriger. Ensuite, j'ai vérifié mon AppDelegate où j'appelais et je initWithNibNamepeux voir qu'en copiant le code, j'ai changé le nom xib, mais j'ai oublié de changer de UIViewControllerclasse. Donc, si aucune solution ne fonctionne pour vous, vérifiez votre initWithNibNameméthode.

Noob
la source
0

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

Alex Bedro
la source