El NSObject
método performSelector:withObject:afterDelay:
me permite invocar un método en el objeto con un argumento de objeto después de un cierto tiempo. No se puede utilizar para métodos con un argumento que no sea de objeto (por ejemplo, ints, floats, structs, punteros que no sean de objeto, etc.).
¿Cuál es la forma más sencilla de lograr lo mismo con un método con un argumento sin objeto? Sé que de forma regular performSelector:withObject:
, la solución es usar NSInvocation
(que por cierto es realmente complicado). Pero no sé cómo manejar la parte del "retraso".
Gracias,
objective-c
cocoa
usuario102008
fuente
fuente
Respuestas:
Esto es lo que solía llamar algo que no podía cambiar usando NSInvocation:
fuente
[theMovie setOrientation: UIInterfaceOrientationPortrait animated:NO]
? ¿O quiere decir que elinvoke
mensaje está en el método que realiza después de la demora?Simplemente envuelva el float, boolean, int o similar en un NSNumber.
Para las estructuras, no conozco una solución útil, pero podría crear una clase ObjC separada que posea dicha estructura.
fuente
nil
paraBOOL
recibir un parámetroNO
(FALSE
)NO USE ESTA RESPUESTA. SOLO LO HE DEJADO PARA FINES HISTÓRICOS. VER LOS COMENTARIOS A CONTINUACIÓN.
Hay un truco simple si es un parámetro BOOL.
Pase nulo por NO y self por SÍ. nil se convierte en el valor BOOL de NO. self se convierte en el valor BOOL de YES.
Este enfoque se rompe si no es un parámetro BOOL.
Asumir que uno mismo es una UIView.
fuente
if ()
prueba, pero es concebible que algún código dependa de que sea 0 o 1, y así ganó No trate un valor de dirección grande como si fuera igual a 1 (YES).self
con una dirección como0x0123400
. Con este enfoque, obtendrá NO en respuesta a SÍ en el 0.4% de los casos. Peor, con esta probabilidad, esta solución puede pasar todas las pruebas y revelar más tarde.Quizás NSValue , solo asegúrese de que sus punteros sigan siendo válidos después del retraso (es decir, no hay objetos asignados en la pila).
fuente
NSValue
(si es posible) lo esperadotype
?Sé que esta es una pregunta antigua, pero si está creando iOS SDK 4+, puede usar bloques para hacer esto con muy poco esfuerzo y hacerlo más legible:
fuente
PerformSelector: WithObject siempre toma un objeto, así que para pasar argumentos como int / double / float, etc ..... Puedes usar algo como esto.
De la misma manera puede usar [NSNumber numberWithInt:] etc .... y en el método de recepción puede convertir el número a su formato como [number int] o [number double].
fuente
Los bloques son el camino a seguir. Puede tener parámetros complejos, seguridad de tipos y es mucho más simple y seguro que la mayoría de las respuestas anteriores aquí. Por ejemplo, podría simplemente escribir:
Los bloques le permiten capturar listas de parámetros arbitrarias, objetos de referencia y variables.
Implementación de respaldo (básico):
Ejemplo:
También vea la respuesta de Michael (+1) para ver otro ejemplo.
fuente
Siempre recomendaría que use NSMutableArray como el objeto para transmitir. Esto se debe a que luego puede pasar varios objetos, como el botón presionado y otros valores. NSNumber, NSInteger y NSString son solo contenedores de algún valor. Asegúrese de que cuando obtenga el objeto de la matriz al que se refiere a un tipo de contenedor correcto. Necesita pasar los contenedores NS. Allí puede probar el valor. Recuerde que los contenedores usan isEqual cuando se comparan valores.
fuente
También quería hacer esto, pero con un método que recibe un parámetro BOOL. Envolviendo el valor bool con NSNumber, NO SE PODÍA PASAR EL VALOR. No tengo ni idea de porqué.
Así que terminé haciendo un truco simple. Pongo el parámetro requerido en otra función ficticia y llamo a esa función usando performSelector, donde withObject = nil;
fuente
-performSelector[...]
método espera un objeto (en lugar de un tipo de datos primitivo), y no sabe que el selector llamado acepta un booleano, tal vez la dirección (valor del puntero) de laNSNumber
instancia se 'envía' ciegamente aBOOL
(= distinto de cero, es decirTRUE
). Quizás el tiempo de ejecución podría ser más inteligente que esto y reconocer un booleano cero envuelto en unNSNumber
!Encuentro que la forma más rápida (pero algo sucia) de hacer esto es invocando objc_msgSend directamente. Sin embargo, es peligroso invocarlo directamente porque necesita leer la documentación y asegurarse de que está utilizando la variante correcta para el tipo de valor devuelto y porque objc_msgSend se define como vararg para la conveniencia del compilador, pero en realidad se implementa como pegamento de ensamblaje rápido . Aquí hay un código usado para llamar a un método delegado - [delegate integerDidChange:] que toma un único argumento entero.
Esto primero guarda el selector ya que vamos a hacer referencia a él varias veces y sería fácil crear un error tipográfico. Luego verifica que el delegado realmente responde al selector; podría ser un protocolo opcional. Luego crea un tipo de puntero de función que especifica la firma real del selector. Tenga en cuenta que todos los mensajes de Objective-C tienen dos primeros argumentos ocultos, el objeto al que se envía el mensaje y el selector que se envía. Luego creamos un puntero de función del tipo apropiado y lo configuramos para que apunte a la función objc_msgSend subyacente. Tenga en cuenta que si el valor de retorno es un flotante o una estructura, debe usar una variante diferente de objc_msgSend. Finalmente, envíe el mensaje utilizando la misma maquinaria que utiliza Objective-C debajo de las hojas.
fuente
Podría usar NSTimer para llamar a un selector:
fuente
yourMethod:
su ejemplo es el temporizador en sí, y no ha pasado nadauserInfo
. Incluso si lo usarauserInfo
, aún tendría que encajar el valor, como sugirieron Daños y Remus Rusanu.Llamar a performSelector con un NSNumber u otro NSValue no funcionará. En lugar de usar el valor de NSValue / NSNumber, lanzará efectivamente el puntero a un int, float o lo que sea y lo usará.
Pero la solución es simple y obvia. Cree la NSInvocation y llame
[invocation performSelector:@selector(invoke) withObject:nil afterDelay:delay]
fuente
Quizás ... ok, muy probablemente, me falta algo, pero ¿por qué no crear un tipo de objeto, digamos NSNumber, como un contenedor para su variable de tipo que no es de objeto, como CGFloat?
fuente