Envié mi aplicación hace poco más de una semana y hoy recibí el temido correo electrónico de rechazo. Me dice que mi aplicación no puede ser aceptada porque estoy usando una API no pública; específicamente, dice:
La API no pública que se incluye en su aplicación es firstResponder.
Ahora, la llamada API ofensiva es en realidad una solución que encontré aquí en SO:
UIWindow *keyWindow = [[UIApplication sharedApplication] keyWindow];
UIView *firstResponder = [keyWindow performSelector:@selector(firstResponder)];
¿Cómo obtengo el primer respondedor actual en la pantalla? Estoy buscando una forma en que mi aplicación no sea rechazada.
objective-c
cocoa-touch
first-responder
Justin Kredible
fuente
fuente
Respuestas:
En una de mis aplicaciones, a menudo quiero que el primer respondedor renuncie si el usuario toca el fondo. Para este propósito escribí una categoría en UIView, que llamo en la UIWindow.
Lo siguiente se basa en eso y debería devolver el primer respondedor.
iOS 7+
Rápido:
Ejemplo de uso en Swift:
fuente
[self.view endEditing:YES]
?Si su objetivo final es renunciar al primer respondedor, esto debería funcionar:
[self.view endEditing:YES]
fuente
Una forma común de manipular al primer respondedor es utilizar acciones específicas nulas. Esta es una forma de enviar un mensaje arbitrario a la cadena de respuesta (comenzando con el primer respondedor), y continuar por la cadena hasta que alguien responda al mensaje (ha implementado un método que coincida con el selector).
Para el caso de descartar el teclado, esta es la forma más efectiva que funcionará sin importar qué ventana o vista responda primero:
Esto debería ser más efectivo que incluso
[self.view.window endEditing:YES]
.(Gracias a BigZaphod por recordarme el concepto)
fuente
Aquí hay una categoría que le permite encontrar rápidamente el primer respondedor llamando
[UIResponder currentFirstResponder]
. Simplemente agregue los siguientes dos archivos a su proyecto:UIResponder + FirstResponder.h
UIResponder + FirstResponder.m
El truco aquí es que enviar una acción a cero la envía al primer respondedor.
(Originalmente publiqué esta respuesta aquí: https://stackoverflow.com/a/14135456/322427 )
fuente
Aquí hay una extensión implementada en Swift basada en la respuesta más excelente de Jakob Egger:
Swift 4
fuente
current
lugar defirst
?No es bonito, pero la forma en que renuncio al primer Respondedor cuando no sé cuál es el respondedor:
Cree un UITextField, ya sea en IB o mediante programación. Hazlo oculto. Vincúlelo a su código si lo hizo en IB.
Luego, cuando desea cerrar el teclado, cambia el respondedor al campo de texto invisible e inmediatamente lo renuncia:
fuente
Para una versión Swift 3 y 4 de la respuesta de nevyn :
fuente
Aquí hay una solución que informa el primer respondedor correcto (muchas otras soluciones no informarán
UIViewController
como el primer respondedor, por ejemplo), no requiere bucle sobre la jerarquía de vista y no utiliza API privadas.Aprovecha el método sendAction de Apple : a: from: forEvent: que ya sabe cómo acceder al primer respondedor.
Solo necesitamos ajustarlo de 2 maneras:
UIResponder
para que pueda ejecutar nuestro propio código en el primer respondedor.UIEvent
para devolver el primer respondedor.Aquí está el código:
fuente
El primer respondedor puede ser cualquier instancia de la clase UIResponder, por lo que hay otras clases que podrían ser el primer respondedor a pesar de las UIViews. Por ejemplo
UIViewController
, también podría ser el primer respondedor.En este resumen , encontrará una forma recursiva de obtener el primer respondedor recorriendo la jerarquía de controladores a partir del rootViewController de las ventanas de la aplicación.
Puede recuperar el primer respondedor haciendo
Sin embargo, si el primer respondedor no es una subclase de UIView o UIViewController, este enfoque fallará.
Para solucionar este problema, podemos hacer un enfoque diferente al crear una categoría
UIResponder
y realizar un poco de magia para poder construir una variedad de todas las instancias vivas de esta clase. Luego, para obtener el primer respondedor, podemos iterar y preguntar a cada objeto si-isFirstResponder
.Este enfoque se puede encontrar implementado en esta otra esencia .
Espero eso ayude.
fuente
Usando Swift y con un objeto específico
UIView
esto podría ayudar:Simplemente colóquelo en su
UIViewController
y úselo así:Tenga en cuenta que el resultado es un valor opcional, por lo que será nulo en caso de que no se encuentre firstResponser en las subvistas de vistas proporcionadas.
fuente
Itere sobre las vistas que podrían ser el primer respondedor y úselas
- (BOOL)isFirstResponder
para determinar si actualmente lo son.fuente
Peter Steinberger acaba de tuitear sobre la notificación privada
UIWindowFirstResponderDidChangeNotification
, que puede observar si desea ver el cambio de firstResponder.fuente
Si solo necesita eliminar el teclado cuando el usuario toca un área de fondo, ¿por qué no agrega un reconocedor de gestos y lo utiliza para enviar el
[[self view] endEditing:YES]
mensaje?puedes agregar el reconocimiento de gestos Tap en el archivo xib o storyboard y conectarlo a una acción,
se parece a esto y luego terminado
fuente
Por si acaso, aquí está la versión Swift del increíble enfoque de Jakob Egger:
fuente
Esto es lo que hice para encontrar qué UITextField es el primer Respondedor cuando el usuario hace clic en Guardar / Cancelar en un ModalViewController:
fuente
Esto es lo que tengo en mi categoría UIViewController. Útil para muchas cosas, incluida la primera respuesta. ¡Los bloques son geniales!
fuente
Con una categoría activada
UIResponder
, es posible pedirle legalmente alUIApplication
objeto que le diga quién es el primer respondedor.Mira esto:
¿Hay alguna forma de preguntarle a una vista de iOS cuál de sus hijos tiene el estado de primer respondedor?
fuente
Puede elegir la siguiente
UIView
extensión para obtenerla (crédito de Daniel) :fuente
Puedes probar también así:
No lo intenté pero parece una buena solución
fuente
La solución de romeo https://stackoverflow.com/a/2799675/661022 es genial, pero noté que el código necesita un bucle más. Estaba trabajando con tableViewController. Edité el guión y luego lo verifiqué. Todo funcionó a la perfección.
Recomiendo probar esto:
fuente
if ([textField isKindOfClass:[UITextField class]])
, permitiendo el uso de uitextview, y podría devolver el primer respondedor.Este es un buen candidato para la recursividad! No es necesario agregar una categoría a UIView.
Uso (desde su controlador de vista):
Código:
fuente
puedes llamar a una API privada así, Apple ignora:
fuente
Versión rápida de la respuesta de @ thomas-müller
fuente
Tengo un enfoque ligeramente diferente al de la mayoría aquí. En lugar de recorrer la colección de vistas buscando la que se ha
isFirstResponder
configurado, yo también envío un mensaje anil
, pero almaceno el receptor (si lo hay), luego devuelvo ese valor para que la persona que llama obtenga la instancia real (de nuevo, si la hay) .Entonces puedo renunciar al primer respondedor, si lo hay, haciendo esto ...
Pero ahora también puedo hacer esto ...
fuente
Me gustaría compartir con ustedes mi implementación para encontrar el primer respondedor en cualquier lugar de UIView. Espero que ayude y lo siento por mi inglés. Gracias
fuente
Código debajo del trabajo.
fuente
Actualización: estaba equivocado. De hecho, puede usar
UIApplication.shared.sendAction(_:to:from:for:)
para llamar al primer respondedor demostrado en este enlace: http://stackoverflow.com/a/14135456/746890 .La mayoría de las respuestas aquí realmente no pueden encontrar el primer respondedor actual si no está en la jerarquía de vistas. Por ejemplo,
AppDelegate
oUIViewController
subclases.Hay una manera de garantizar que lo encuentre incluso si el primer objeto de respuesta no es un
UIView
.Primero implementemos una versión inversa de la misma, usando la
next
propiedad deUIResponder
:Con esta propiedad calculada, podemos encontrar el primer respondedor actual de abajo hacia arriba, incluso si no lo es
UIView
. Por ejemplo, de aview
a laUIViewController
quién lo administra, si el controlador de vista es el primer respondedor.Sin embargo, todavía necesitamos una resolución de arriba hacia abajo, una sola
var
para obtener el primer respondedor actual.Primero con la jerarquía de vistas:
Esto buscará el primer respondedor al revés, y si no puede encontrarlo, le dirá a sus subvistas que hagan lo mismo (porque su subvista
next
no es necesariamente ella misma). Con esto podemos encontrarlo desde cualquier punto de vista, incluidoUIWindow
.Y finalmente, podemos construir esto:
Entonces, cuando desee recuperar el primer respondedor, puede llamar a:
fuente
La forma más sencilla de encontrar el primer respondedor:
Próximo paso:
Uso: solo obténgalo
UIResponder.actualFirst
para sus propios fines.fuente