Error de "selector no reconocido enviado a instancia" en Objective-C

155

Creé un botón y agregué una acción para él, pero tan pronto como se invocó, recibí este error:

-[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 es mi 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(@"---");
}
Hola Mundo
fuente

Respuestas:

187

Parece que no está manejando la memoria del controlador de vista correctamente y se está desasignando en algún momento, lo que hace que el numberButtonClicked:método se envíe a otro objeto que ahora está ocupando la memoria que el controlador de vista estaba ocupando anteriormente ...

Asegúrese de retener / liberar correctamente su controlador de vista.

Jasarien
fuente
105
Ese es un diagnóstico muy astuto de muy pocas líneas de código.
Michael Morrison
41
OK, entonces se identificó el problema ... pero "Asegúrese de retener / liberar correctamente su controlador de vista". Es una sugerencia, no una solución.
Alex Gray
12
@Alex Grey, ¿qué? La gestión adecuada de la memoria en el controlador de vista resolvió el problema ... ¿No entiendo cómo eso no es una solución?
Jasarien
28
correcto. aunque esto parece ser "la solución" ... y puedo estar en minoría (aunque todavía logro existir), pero la conexión entre el problema y la solución no es obvia de inmediato. por ejemplo, me encuentro -[NSWindow end]: unrecognized selector sent to instance 0x100523e80 y aunque me doy cuenta de las similitudes con el OP, e incluso posiblemente la causa del problema de su respuesta, la implementación de una solución no es inmediatamente obvia
Alex Gray
12
Es inmediatamente obvio. Su administración de memoria NSWindow no es correcta en algún lugar de la línea. Revisa su ciclo de vida y corrígelo.
Jasarien
127

Para aquellos que llegan aquí a través de Google como lo hice yo, lo que probablemente pertenece más a Xcode 4.2 + / iOS 5+ más, con ARC. Tuve el mismo error " selector no reconocido enviado a la instancia ". En mi caso, tenía una acción objetivo de UIButton configurada para pasarse a sí misma como parámetro del remitente, pero luego me di cuenta de que no la necesitaba y la eliminé en el código. Entonces, algo como:

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

Se cambió a:

- (IBAction)buttonPressed {

Al hacer clic con el botón derecho en el botón UIB en cuestión, se mostró que el evento Touch Up Inside estaba asociado con el botón de los controladores de vista Presionado: método. Eliminar esto y reasignarlo al método modificado funcionó de maravilla.

LeonardChallis
fuente
Esto fue muy útil, aunque creo que su propia pregunta y respuesta lo haría más fácil de encontrar.
Curtis Inderwiesche
@LeonardChallis ¿Cómo puede hacer referencia al remitente en buttonPressed si no se pasa como parámetro?
zakdances
8
Muy útil respuesta. Me encontré con este problema exacto y su solución fue exactamente la correcta. Estaba siguiendo la clase Stanford iOS en iTunesU cuando esto sucedió. ¡Gracias de nuevo por su respuesta!
Marshall Alsup
1
@LeonardChallis Gracias. Agregué una respuesta complementaria a tu respuesta.
1.21 gigavatios
1
Estaba luchando con un problema similar, eliminé el parámetro del remitente de la función del selector y luego me pregunté cómo obtener el remitente. En mi caso, recibí el error porque olvidé poner dos puntos después de la devolución de llamada del selector, lo que provocó una falta de coincidencia de la secuencia de llamada. Con los dos puntos, puedo mantener el argumento del remitente.
74

Esta fue la principal respuesta de Google para este problema, pero tenía una causa / resultado diferente: pensé en agregar mis dos centavos en caso de que otros se toparan con este problema.

Tuve un problema similar esta mañana. Descubrí que si hace clic derecho en el elemento de la interfaz de usuario que le da el problema, puede ver qué conexiones se han creado. En mi caso, tenía un botón conectado a dos acciones. Eliminé las acciones del menú contextual y las volví a conectar y mi problema se solucionó.

Así que asegúrese de que sus acciones estén cableadas correctamente.

Chris K
fuente
Este fue mi problema. Cambié el nombre de una función y cambié mi código, pero no cambié la conexión en el archivo xib.
BFTrick
2
¡GRACIAS! Resultó que tenía tres métodos que había eliminado y a los que todavía hacía referencia. Me molesta por una semana!
erdekhayser
25

OK, tengo que meterme aquí. El OP creó dinámicamente el botón . Tuve un problema similar y la respuesta (después de horas de caza) es tan simple que me enfermó.

Cuando usas:

action:@selector(xxxButtonClick:)

or (as in my case)

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

Si coloca dos puntos al final de la cadena, pasará al remitente. Si no coloca los dos puntos al final de la cadena, no lo hará, y el receptor recibirá un error si espera uno. Es fácil perder los dos puntos si está creando dinámicamente el nombre del evento.

Las opciones de código del receptor se ven así:

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

Como de costumbre, siempre se pierde la respuesta obvia.

Craig H.
fuente
1
¡Muchas gracias! Este fue mi problema (no poner dos puntos ':' al final del nombre del selector). ¿Cómo es que casi siempre son las cosas simples más estúpidas que nos tienen a los geeks golpeándonos la cabeza contra la pared a las 3 de la mañana? ¡De verdad gracias!
TWright
23

En mi caso, la función no esperaba un argumento, pero el botón se configuró para enviar uno que causara el error. Para solucionar esto, tuve que volver a cablear el controlador de eventos.

Aquí está mi función:

ingrese la descripción de la imagen aquí

Observe que no contiene argumentos.

Aquí hay una imagen de la configuración de mi botón (haga clic derecho en el botón para verlo):

ingrese la descripción de la imagen aquí

Tenga en cuenta que hay 3 controladores de eventos.

Para solucionar esto, tuve que eliminar cada uno de los elementos del evento ya que uno de ellos estaba enviando una referencia a sí mismo a la función enterPressed. Para eliminar estos elementos, hice clic en el pequeño icono x al lado del nombre de cada elemento hasta que no se mostraron.

ingrese la descripción de la imagen aquí

Luego tuve que volver a conectar el botón al evento. Para hacer esto, mantenga presionada la tecla Control y luego arrastre una línea desde el botón a la acción. Debería decir "Acción de conexión". Nota: Tuve que reiniciar XCode para que esto funcione por alguna razón; de lo contrario, solo me permite insertar acciones (también conocido como crear una nueva acción) encima o debajo de la función.

ingrese la descripción de la imagen aquí

Ahora debería tener un único controlador de eventos conectado al evento de botón que no pasa argumentos:

ingrese la descripción de la imagen aquí

Esta respuesta complementa la respuesta de @Leonard Challis, que también deberías leer.

1,21 gigavatios
fuente
14

Esto también puede suceder si no configura la "Clase" de la vista en el generador de interfaces.

usuario1658373
fuente
Agh gracias! Esto estaba causando que mi aplicación se bloqueara en una secuencia, solo olvidé configurar la clase del controlador.
Eichhörnchen
¿Por qué necesita saber la clase? Estoy tratando de usar una UITableViewSection como UIView, y obtengo este error. El compilador dice que UITableViewSection no existe, por lo que supongo que es interno a UIKit.
Ian Warburton
13

En mi caso, estaba usando NSNotificationCenter e intentaba usar un selector que no tomaba argumentos, pero agregaba dos puntos. Eliminar el colon solucionó el problema.

Cuando use un nombre de selector, no use dos puntos finales si no hay argumentos. Si hay un argumento, use dos puntos finales. Si hay más de un argumento, debe nombrarlos junto con dos puntos finales para cada argumento.

Vea la respuesta de Adam Rosenfield aquí: ¿ Selectores en Objective-C?

Nathan Garabedian
fuente
11

Tuve este problema con un proyecto Swift donde estoy creando los botones dinámicamente. Código de 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).")
}

La solución fue agregar dos puntos ':' después de la acción: ej.

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

Ejemplo completo aquí: https://developer.apple.com/library/content/samplecode/UICatalog/Listings/Swift_UIKitCatalog_DefaultToolbarViewController_swift.html

FredL
fuente
Justo después de seguir el tutorial y leer una pista sobre este mismo problema, me enamoré de él: D
user2161301
6

La causa más obvia de esto (incluido para completar) es lanzar incorrectamente un puntero y llamar a un método de la clase incorrecta.

NSArray* array = [[NSArray alloc] init];
[(NSDictionary*)array objectForKey: key]; // array is not a dictionary, hence exception
devios1
fuente
Esta es una buena pista: no subclasificar una vista o un objeto de datos (por ejemplo, al no agregar el nombre de la subclase) es otra forma de
Brad M
4

También tuve el mismo problema.

Eliminé mi uibutton en mi guión gráfico y lo recreé ... ahora todo funciona bien.

Yohan Dahmani
fuente
3

Tuve un problema similar, pero para mí la solución fue ligeramente diferente. En mi caso, utilicé una categoría para extender una clase existente (UIImage para algunas capacidades de cambio de tamaño; vea este tutorial en caso de que esté interesado) y olvidé agregar el archivo * .m al destino de compilación. Error estúpido, pero no siempre es obvio cuando sucede dónde buscar. Pensé que valía la pena compartir ...

Mirko Jahn
fuente
3

Esto me sucedió porque borré accidentalmente la "función @IBAction ..." dentro de mi código de clase UIViewcontroller, por lo que en el Storyboard se creó el Outlet de referencia, pero en el tiempo de ejecución había alguna función para procesarlo.

La solución fue eliminar la referencia de Outlet dentro del inspector de propiedades y luego volver a crearla arrastrando con la tecla de comando al código de clase.

¡Espero eso ayude!

Guillermo
fuente
Del mismo modo, esto también me sucedió cuando el botón hacía referencia a una función que ya no existía.
Josh Wolff
2

Creo que debería usar el vacío, en lugar del IBAction en el tipo de retorno. porque definiste un botón mediante programación.

Fa Shapouri
fuente
2

Otra posible solución: agregue '-ObjC' a sus argumentos de enlazador.

La explicación completa está aquí: categorías de Objective-C en la biblioteca estática

Creo que la esencia es: si la categoría se define en una biblioteca con la que está vinculando estáticamente, el vinculador no es lo suficientemente inteligente como para vincular en los métodos de categoría. El indicador de arriba hace que el enlazador se vincule en todas las clases y categorías objetivas de C, no solo en las que cree que deben basarse en el análisis de su fuente. (Por favor, siéntase libre de sintonizar o corregir esa respuesta. Conozco los idiomas vinculados, así que solo estoy parroteando aquí).

Russ Egan
fuente
2

Tuve el mismo error y descubrí lo siguiente:

Cuando usas el código

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

Puede pensar que está buscando el selector:

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

Pero en realidad está buscando el selector:

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

Ese selector no existe, por lo que obtienes el bloqueo.

Puede cambiar el selector para recibir el remitente (id) para resolver el error.

Pero, ¿qué sucede si tiene otras funciones que llaman a la función de actualización sin proporcionar un remitente? Necesita una función que funcione para ambos. La solución fácil es agregar otra función:

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

Y luego modifique el código desplegable de actualización para llamar a ese selector en su lugar:

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

También estoy haciendo el curso de Stanford iOS en una Mac anterior que no se puede actualizar a la versión más reciente de Mac OSX. Así que todavía estoy compilando para iOS 6.1, y esto resolvió el problema para mí.

Orgullo de Joseph
fuente
2

En mi caso, resolví el problema después de 2 horas:

El remitente (un elemento tabBar) no tenía ninguna salida de referencia . Así que no apuntaba a ninguna parte.

Simplemente cree una salida de referencia correspondiente a su función.

Espero que esto pueda ayudarlos.

André DS
fuente
Solo para agregar, en mi caso, olvidé transferir un puerto IBActiona Swift. Por lo tanto, se quejaba de que quería llamar a esa función, pero no se pudo encontrar.
DevNebulae
1

Actualmente estoy aprendiendo el desarrollo de iOS y revisando el libro "Beginning iOS6 Development" de aPress. Recibí el mismo error en el Capítulo 10: Storyboards.

Me tomó dos días descubrirlo, pero descubrí que accidentalmente configuré la etiqueta de la celda TableView en 1 cuando no debería haberlo hecho. Para cualquier otra persona que esté haciendo este libro y reciba un error similar, espero que esto ayude.

¡Realmente espero que los errores futuros en mi código sean más fáciles de encontrar! jajaja. El error de depuración no hizo nada para empujarme en la dirección correcta para resolverlo (o al menos soy demasiado nuevo para entender al depurador, jajaja).

Shannon Cole
fuente
1

En mi caso, estaba usando un UIWebView y pasé un NSString en el segundo parámetro en lugar de un NSURL. Entonces sospecho que los tipos de clase incorrectos pasados ​​a una función pueden causar este error.

jbaylina
fuente
1

.. Y ahora el mío

Tenía el botón vinculado a un método que accedía al parámetro de otro botón y funcionó muy bien PERO tan pronto como intenté hacer algo con el botón en sí, tuve un bloqueo. Durante la compilación, no se ha mostrado ningún error. ¿Solución?

No pude vincular el botón al propietario del archivo. Entonces, si alguien aquí es tan estúpido como yo, prueba esto :)

usuario2875404
fuente
1

Otra solución / caso ligeramente diferente.

Estoy usando Xamarin y MvvmCross e intentaba vincular el UIButton a un ViewModel. Tenía el UIButton conectado a un Outlet y un TouchUpInside.

Cuando enlazo solo uso el Outlet:

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

Todo lo que tenía que hacer era eliminar la conexión de acción (TouchUpInside) en XCode y eso lo resolvió.

PD: Supongo que esto está en su base todo relacionado con las respuestas anteriores y con @Chris Kaminski en particular, pero espero que esto ayude a alguien ...

Salud.

YKa
fuente
1

Tuve el mismo problema. El problema para mí fue que un botón tenía dos métodos de acción. Lo que hice fue crear un primer método de acción para mi botón y luego lo eliminé en el controlador de vista, pero olvidé desconectar la conexión en el guión gráfico principal en el inspector de conexiones. Entonces, cuando agregué un segundo método de acción, ahora había dos métodos de acción para un botón, lo que causó el error.

Harshil.Chokshi
fuente
1

Para mí, fue una conexión sobrante creada en el creador de interfaces bij ctrl-dragging. El nombre de la conexión interrumpida estaba en el registro de errores.

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

Tuve una acción vinculada a un botón. Al presionar el botón se bloqueó la aplicación porque el Outlet ya no existía en mi código. Buscar el nombre en el registro me llevó a él en el guión gráfico. ¡Lo eliminé y el accidente desapareció!

Tom Brinkkemper
fuente
0

Estoy respondiendo a Leonard Challis, ya que también estaba tomando la clase C193P de Stanford iOS, como era el usuario "oli206"

"Finalización de la aplicación debido a la excepción no detectada 'NSInvalidArgumentException', razón:"

El problema era que tenía el botón "Entrar" en la calculadora conectado dos veces, y un amigo señaló que al inspeccionar el botón en el Guión gráfico se mostraba que 2 entradas estaban en los atributos "Retocar adentro" cuando hice clic derecho en el botón "Entrar". Borrar uno de los dos "Eventos enviados" "Resolver dentro" resolvió el problema.

Esto demostró que el problema se desencadena (para la clase de video C193P en el Tutorial de la Calculadora en la Asignación 1) como 2 eventos enviados, uno de los cuales estaba causando la excepción.

Peter_de_NYC
fuente
Tenía 3 entradas de alguna manera. :)
1.21 gigavatios
0

Puede suceder cuando no asigna ViewController a ViewControllerScene en InterfaceBuilder. Por lo tanto, ViewController.m no está conectado a ninguna escena.

Vincent
fuente
0

Incluyendo mi parte. Me quedé atrapado en esto por un tiempo, hasta que me di cuenta de que había creado un proyecto con ARC (referencia de conteo automático) deshabilitado. Un ajuste rápido a SÍ en esa opción resolvió mi problema.

caiocpricci2
fuente
0

Otra causa realmente tonta de esto es tener el selector definido en la interfaz (.h) pero no en la implementación (.m) (error tipográfico)

jla
fuente
0

Otra razón / solución para agregar a la lista. Este es causado por iOS6.0 (y / o mala programación). En versiones anteriores, el selector coincidiría si los tipos de parámetros coincidieran, pero en iOS 6.0 tuve bloqueos en el código que funcionaba anteriormente donde el nombre del parámetro no era correcto.

Estaba haciendo algo como

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

pero en la definición (tanto .h como .m) tuve

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

Esto funcionó bien en iOS5 pero no en 6, incluso la misma compilación implementada en diferentes dispositivos.

De todos modos, no entiendo por qué el compilador no podría decirme esto: el problema se resolvió.

Tim T
fuente
0

Esto también puede suceder cuando desea establecer una propiedad de un ControllerA en una propiedad pública dentro de una clase personalizada de ControllerB y aún no ha configurado la "Clase personalizada" dentro del inspector de identidad en los guiones gráficos.

Francisco Gutiérrez
fuente
0

Mi problema y solución fueron diferentes y pensé que debería publicarlo aquí para que los futuros lectores puedan evitar que su cabeza golpee la pared.

Estaba asignando diferentes xib al mismo UIVIewController e incluso después de buscar en todas partes no pude encontrar cómo corregirlo. Luego revisé mi AppDelegate donde estaba llamando initWithNibNamey puedo ver que mientras copiaba el código, cambié el nombre de xib, pero olvidé cambiar la UIViewControllerclase. Entonces, si ninguna de las soluciones funciona para usted, verifique su initWithNibNamemétodo.

novato
fuente
0

Me pasó a mí debido a argumentos de restricción conflictivos.

Alex Bedro
fuente