Obtenga el primer respondedor actual sin usar una API privada


340

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.


55
En lugar de iterar sobre las vistas, puede usar esta magia verdaderamente brillante : stackoverflow.com/a/14135456/746890
Chris Nolet

Respuestas:


338

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.

@implementation UIView (FindFirstResponder)
- (id)findFirstResponder
{
    if (self.isFirstResponder) {
        return self;        
    }
    for (UIView *subView in self.subviews) {
        id responder = [subView findFirstResponder];
        if (responder) return responder;
    }
    return nil;
}
@end

iOS 7+

- (id)findFirstResponder
{
    if (self.isFirstResponder) {
        return self;
    }
    for (UIView *subView in self.view.subviews) {
        if ([subView isFirstResponder]) {
            return subView;
        }
    }
    return nil;
}

Rápido:

extension UIView {
    var firstResponder: UIView? {
        guard !isFirstResponder else { return self }

        for subview in subviews {
            if let firstResponder = subview.firstResponder {
                return firstResponder
            }
        }

        return nil
    }
}

Ejemplo de uso en Swift:

if let firstResponder = view.window?.firstResponder {
    // do something with `firstResponder`
}

278
¿Por qué es esta una mejor solución que simplemente llamar [self.view endEditing:YES]?
Tim Sullivan el

69
@Tim, no podría hacer eso. Obviamente, es una forma mucho más simple de renunciar al primer respondedor. Sin embargo, no ayuda con las preguntas originales, que fueron identificar al primer respondedor.
Thomas Müller

17
Además, esta es una mejor respuesta porque es posible que desee hacer algo más con el primer respondedor que renunciar a ella ...
Erik B

3
Cabe señalar que esto solo encuentra UIViews, no otros UIResponders que también podrían ser el primer respondedor (por ejemplo, UIViewController o UIApplication).
Patrick Pijnappel

10
¿Por qué la diferencia para iOS 7? ¿No querrías también recurrir en ese caso?
Peter DeWeese

531

Si su objetivo final es renunciar al primer respondedor, esto debería funcionar: [self.view endEditing:YES]


122
Para todos ustedes que dicen que esta es la respuesta a la "pregunta", ¿pueden echar un vistazo a la pregunta real? La pregunta pregunta cómo obtener el primer respondedor actual. No cómo renunciar al primer respondedor.
Justin Kredible el

2
¿Y dónde deberíamos llamar a esto self.view endEditing?
user4951

8
Es cierto que esto no responde exactamente la pregunta, pero claramente es una respuesta muy útil. ¡Gracias!
NovaJoe

66
+1 incluso si no es una respuesta a la pregunta. ¿Por qué? Porque muchos vienen aquí con una pregunta en mente que esta respuesta responde :) Al menos 267 (en este momento) de ellos ...
Rok Jarc

1
Esto no responde la pregunta.
Sasho

186

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:

[[UIApplication sharedApplication] sendAction:@selector(resignFirstResponder) to:nil from:nil forEvent:nil];

Esto debería ser más efectivo que incluso [self.view.window endEditing:YES].

(Gracias a BigZaphod por recordarme el concepto)


44
Esto es genial. Posiblemente el mejor truco de Cocoa Touch que he visto en SO todavía. Me ayudó a no tener fin!
mluisbrown 01 de

Esta es, con diferencia, la mejor solución, ¡un millón de gracias! esto es mucho mejor que la solución anterior, porque funciona incluso en el campo de texto activo es parte de la vista accesoria del teclado (en ese caso no es parte de nuestra jerarquía de vistas)
Pizzaiola Gorgonzola

2
Esta solución es la solución de mejores prácticas. El sistema ya sabe quién es el primer respondedor, no hay necesidad de encontrarlo.
Leftspin

2
Quiero dar esta respuesta a más de un voto a favor. Esto es genial genio.
Reid Main

1
devios1: la respuesta de Jakob es exactamente lo que pide la pregunta, pero es un truco en la parte superior del sistema de respuesta, en lugar de utilizar el sistema de respuesta de la manera en que fue diseñado. Esto es más limpio y logra lo que la mayoría de la gente viene a esta pregunta, y también de una sola vez. (Por supuesto, puede enviar cualquier mensaje de estilo de acción de destino, y no solo resignFirstResponder).
nevyn

98

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

#import <Cocoa/Cocoa.h>
@interface UIResponder (FirstResponder)
    +(id)currentFirstResponder;
@end

UIResponder + FirstResponder.m

#import "UIResponder+FirstResponder.h"
static __weak id currentFirstResponder;
@implementation UIResponder (FirstResponder)
    +(id)currentFirstResponder {
         currentFirstResponder = nil;
         [[UIApplication sharedApplication] sendAction:@selector(findFirstResponder:) to:nil from:nil forEvent:nil];
         return currentFirstResponder;
    }
    -(void)findFirstResponder:(id)sender {
        currentFirstResponder = self;
    }
@end

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 )


1
+1 Esta es la solución más elegante para el problema (y la pregunta real) que he visto todavía. Reutilizable y eficiente! ¡Vota esta respuesta!
devios1

3
Bravo. Esto podría ser el truco más hermoso y limpio que he visto para Objc ...
Aviel Gross

Muy agradable. Debería funcionar realmente bien para poder preguntarle al primer respondedor quién (si alguien) en la cadena manejará un método de acción particular si se enviara. Puede usar esto para habilitar o deshabilitar los controles en función de si se pueden manejar. Contestaré mi propia pregunta sobre esto y haré referencia a tu respuesta.
Benjohn


Advertencia: esto no funciona si comienza a agregar varias ventanas. Desafortunadamente, no puedo señalar una causa más allá de eso todavía.
Heath Borders

41

Aquí hay una extensión implementada en Swift basada en la respuesta más excelente de Jakob Egger:

import UIKit

extension UIResponder {
    // Swift 1.2 finally supports static vars!. If you use 1.1 see: 
    // http://stackoverflow.com/a/24924535/385979
    private weak static var _currentFirstResponder: UIResponder? = nil

    public class func currentFirstResponder() -> UIResponder? {
        UIResponder._currentFirstResponder = nil
        UIApplication.sharedApplication().sendAction("findFirstResponder:", to: nil, from: nil, forEvent: nil)
        return UIResponder._currentFirstResponder
    }

    internal func findFirstResponder(sender: AnyObject) {
        UIResponder._currentFirstResponder = self
    }
}

Swift 4

import UIKit    

extension UIResponder {
    private weak static var _currentFirstResponder: UIResponder? = nil

    public static var current: UIResponder? {
        UIResponder._currentFirstResponder = nil
        UIApplication.shared.sendAction(#selector(findFirstResponder(sender:)), to: nil, from: nil, for: nil)
        return UIResponder._currentFirstResponder
    }

    @objc internal func findFirstResponder(sender: AnyObject) {
        UIResponder._currentFirstResponder = self
    }
}

1
Respuesta modificada para swift1.2 donde se admiten var estáticas.
nacho4d

Hola, cuando imprimo el resultado de esto en una nueva aplicación de vista única en viewDidAppear () me sale nulo. ¿No debería ser la vista la primera respuesta?
farhadf

@LinusGeffarth ¿No tiene más sentido llamar al método estático en currentlugar de first?
Code Commander

Supongo que sí, lo editó. Parece que se me cayó la parte importante al abreviar el nombre de la variable.
LinusGeffarth

29

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:

    [self.invisibleField becomeFirstResponder];
    [self.invisibleField resignFirstResponder];

61
Esto es horrible y genial al mismo tiempo. Agradable.
Alex Wayne

44
Me parece un poco peligroso: Apple puede decidir un día que hacer que un control oculto se convierta en el primer respondedor no es un comportamiento intencionado y "arreglar" iOS para que no vuelva a hacer esto, y luego su truco puede dejar de funcionar.
Thomas Tempelmann

2
O puede asignar el firstResponder a un UITextField que esté visible actualmente y luego llamar a resignFirstResponder en ese campo de texto en particular. Esto elimina la necesidad de crear una vista oculta. De todos modos, +1.
Swifty McSwifterton

3
Prefiero pensar que es horrible ... puede cambiar la distribución del teclado (o la vista de entrada) antes de ocultarlo
Daniel

19

Para una versión Swift 3 y 4 de la respuesta de nevyn :

UIApplication.shared.sendAction(#selector(UIView.resignFirstResponder), to: nil, from: nil, for: nil)

10

Aquí hay una solución que informa el primer respondedor correcto (muchas otras soluciones no informarán UIViewControllercomo 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:

  • Extienda UIResponderpara que pueda ejecutar nuestro propio código en el primer respondedor.
  • Subclase UIEventpara devolver el primer respondedor.

Aquí está el código:

@interface ABCFirstResponderEvent : UIEvent
@property (nonatomic, strong) UIResponder *firstResponder;
@end

@implementation ABCFirstResponderEvent
@end

@implementation UIResponder (ABCFirstResponder)
- (void)abc_findFirstResponder:(id)sender event:(ABCFirstResponderEvent *)event {
    event.firstResponder = self;
}
@end

@implementation ViewController

+ (UIResponder *)firstResponder {
    ABCFirstResponderEvent *event = [ABCFirstResponderEvent new];
    [[UIApplication sharedApplication] sendAction:@selector(abc_findFirstResponder:event:) to:nil from:nil forEvent:event];
    return event.firstResponder;
}

@end

7

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

- (void)foo
{
    // Get the first responder
    id firstResponder = [UIResponder firstResponder];

    // Do whatever you want
    [firstResponder resignFirstResponder];      
}

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 UIRespondery 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.


7

Usando Swift y con un objeto específicoUIView esto podría ayudar:

func findFirstResponder(inView view: UIView) -> UIView? {
    for subView in view.subviews as! [UIView] {
        if subView.isFirstResponder() {
            return subView
        }

        if let recursiveSubView = self.findFirstResponder(inView: subView) {
            return recursiveSubView
        }
    }

    return nil
}

Simplemente colóquelo en su UIViewControllery úselo así:

let firstResponder = self.findFirstResponder(inView: self.view)

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.


5

Itere sobre las vistas que podrían ser el primer respondedor y úselas - (BOOL)isFirstResponderpara determinar si actualmente lo son.


4

Peter Steinberger acaba de tuitear sobre la notificación privada UIWindowFirstResponderDidChangeNotification, que puede observar si desea ver el cambio de firstResponder.


Lo rechazan porque usar una API privada, tal vez usar una notificación privada también podría ser una mala idea ...
Laszlo

4

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

- (IBAction)displayGestureForTapRecognizer:(UITapGestureRecognizer *)recognizer{
     [[self view] endEditing:YES];
}

Esto funciono muy bien para mi. Elegí una conexión a una vista en el Xib, y puedo agregar vistas adicionales para invocar esto en Referencing Outlet Collections
James Perih

4

Por si acaso, aquí está la versión Swift del increíble enfoque de Jakob Egger:

import UIKit

private weak var currentFirstResponder: UIResponder?

extension UIResponder {

    static func firstResponder() -> UIResponder? {
        currentFirstResponder = nil
        UIApplication.sharedApplication().sendAction(#selector(self.findFirstResponder(_:)), to: nil, from: nil, forEvent: nil)
        return currentFirstResponder
    }

    func findFirstResponder(sender: AnyObject) {
        currentFirstResponder = self
    }

}

3

Esto es lo que hice para encontrar qué UITextField es el primer Respondedor cuando el usuario hace clic en Guardar / Cancelar en un ModalViewController:

    NSArray *subviews = [self.tableView subviews];

for (id cell in subviews ) 
{
    if ([cell isKindOfClass:[UITableViewCell class]]) 
    {
        UITableViewCell *aCell = cell;
        NSArray *cellContentViews = [[aCell contentView] subviews];
        for (id textField in cellContentViews) 
        {
            if ([textField isKindOfClass:[UITextField class]]) 
            {
                UITextField *theTextField = textField;
                if ([theTextField isFirstResponder]) {
                    [theTextField resignFirstResponder];
                }

            }
        }

    }

}

2

Esto es lo que tengo en mi categoría UIViewController. Útil para muchas cosas, incluida la primera respuesta. ¡Los bloques son geniales!

- (UIView*) enumerateAllSubviewsOf: (UIView*) aView UsingBlock: (BOOL (^)( UIView* aView )) aBlock {

 for ( UIView* aSubView in aView.subviews ) {
  if( aBlock( aSubView )) {
   return aSubView;
  } else if( ! [ aSubView isKindOfClass: [ UIControl class ]] ){
   UIView* result = [ self enumerateAllSubviewsOf: aSubView UsingBlock: aBlock ];

   if( result != nil ) {
    return result;
   }
  }
 }    

 return nil;
}

- (UIView*) enumerateAllSubviewsUsingBlock: (BOOL (^)( UIView* aView )) aBlock {
 return [ self enumerateAllSubviewsOf: self.view UsingBlock: aBlock ];
}

- (UIView*) findFirstResponder {
 return [ self enumerateAllSubviewsUsingBlock:^BOOL(UIView *aView) {
  if( [ aView isFirstResponder ] ) {
   return YES;
  }

  return NO;
 }];
}


2

Puede elegir la siguiente UIViewextensión para obtenerla (crédito de Daniel) :

extension UIView {
    var firstResponder: UIView? {
        guard !isFirstResponder else { return self }
        return subviews.first(where: {$0.firstResponder != nil })
    }
}

1

Puedes probar también así:

- (void) touchesBegan: (NSSet *) touches withEvent: (UIEvent *) event { 

    for (id textField in self.view.subviews) {

        if ([textField isKindOfClass:[UITextField class]] && [textField isFirstResponder]) {
            [textField resignFirstResponder];
        }
    }
} 

No lo intenté pero parece una buena solución


1

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:

- (void)findFirstResponder
{
    NSArray *subviews = [self.tableView subviews];
    for (id subv in subviews )
    {
        for (id cell in [subv subviews] ) {
            if ([cell isKindOfClass:[UITableViewCell class]])
            {
                UITableViewCell *aCell = cell;
                NSArray *cellContentViews = [[aCell contentView] subviews];
                for (id textField in cellContentViews)
                {
                    if ([textField isKindOfClass:[UITextField class]])
                    {
                        UITextField *theTextField = textField;
                        if ([theTextField isFirstResponder]) {
                            NSLog(@"current textField: %@", theTextField);
                            NSLog(@"current textFields's superview: %@", [theTextField superview]);
                        }
                    }
                }
            }
        }
    }
}

¡Gracias! Tienes razón, la mayoría de las respuestas presentadas aquí no son una solución cuando trabajas con uitableview. Podría simplificar mucho su código, incluso eliminar el if if ([textField isKindOfClass:[UITextField class]]), permitiendo el uso de uitextview, y podría devolver el primer respondedor.
Frade

1

Este es un buen candidato para la recursividad! No es necesario agregar una categoría a UIView.

Uso (desde su controlador de vista):

UIView *firstResponder = [self findFirstResponder:[self view]];

Código:

// This is a recursive function
- (UIView *)findFirstResponder:(UIView *)view {

    if ([view isFirstResponder]) return view; // Base case

    for (UIView *subView in [view subviews]) {
        if ([self findFirstResponder:subView]) return subView; // Recursion
    }
    return nil;
}

1

puedes llamar a una API privada así, Apple ignora:

UIWindow *keyWindow = [[UIApplication sharedApplication] keyWindow];
SEL sel = NSSelectorFromString(@"firstResponder");
UIView   *firstResponder = [keyWindow performSelector:sel];

1
pero ... use 'respondsToSelector' para verificar
ibcker

Verifico 'respondsToSelector' ahora pero aún recibo una advertencia, esto podría ser inseguro. ¿Puedo deshacerme de la advertencia de alguna manera?
Ecth

1

Versión rápida de la respuesta de @ thomas-müller

extension UIView {

    func firstResponder() -> UIView? {
        if self.isFirstResponder() {
            return self
        }

        for subview in self.subviews {
            if let firstResponder = subview.firstResponder() {
                return firstResponder
            }
        }

        return nil
    }

}

1

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 isFirstResponderconfigurado, yo también envío un mensaje a nil, 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) .

import UIKit

private var _foundFirstResponder: UIResponder? = nil

extension UIResponder{

    static var first:UIResponder?{

        // Sending an action to 'nil' implicitly sends it to the
        // first responder, where we simply capture it for return
        UIApplication.shared.sendAction(#selector(UIResponder.storeFirstResponder(_:)), to: nil, from: nil, for: nil)

        // The following 'defer' statement executes after the return
        // While I could use a weak ref and eliminate this, I prefer a
        // hard ref which I explicitly clear as it's better for race conditions
        defer {
            _foundFirstResponder = nil
        }

        return _foundFirstResponder
    }

    @objc func storeFirstResponder(_ sender: AnyObject) {
        _foundFirstResponder = self
    }
}

Entonces puedo renunciar al primer respondedor, si lo hay, haciendo esto ...

return UIResponder.first?.resignFirstResponder()

Pero ahora también puedo hacer esto ...

if let firstResponderTextField = UIResponder?.first as? UITextField {
    // bla
}

1

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

+ (UIView *) findFirstResponder:(UIView *) _view {

    UIView *retorno;

    for (id subView in _view.subviews) {

        if ([subView isFirstResponder])
        return subView;

        if ([subView isKindOfClass:[UIView class]]) {
            UIView *v = subView;

            if ([v.subviews count] > 0) {
                retorno = [self findFirstResponder:v];
                if ([retorno isFirstResponder]) {
                    return retorno;
                }
            }
        }
    }

    return retorno;
}

0

Código debajo del trabajo.

- (id)ht_findFirstResponder
{
    //ignore hit test fail view
    if (self.userInteractionEnabled == NO || self.alpha <= 0.01 || self.hidden == YES) {
        return nil;
    }
    if ([self isKindOfClass:[UIControl class]] && [(UIControl *)self isEnabled] == NO) {
        return nil;
    }

    //ignore bound out screen
    if (CGRectIntersectsRect(self.frame, [UIApplication sharedApplication].keyWindow.bounds) == NO) {
        return nil;
    }

    if ([self isFirstResponder]) {
        return self;
    }

    for (UIView *subView in self.subviews) {
        id result = [subView ht_findFirstResponder];
        if (result) {
            return result;
        }
    }
    return nil;
}   

0

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, AppDelegateo UIViewControllersubclases.

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 nextpropiedad de UIResponder:

extension UIResponder {
    var nextFirstResponder: UIResponder? {
        return isFirstResponder ? self : next?.nextFirstResponder
    }
}

Con esta propiedad calculada, podemos encontrar el primer respondedor actual de abajo hacia arriba, incluso si no lo es UIView. Por ejemplo, de a viewa 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 varpara obtener el primer respondedor actual.

Primero con la jerarquía de vistas:

extension UIView {
    var previousFirstResponder: UIResponder? {
        return nextFirstResponder ?? subviews.compactMap { $0.previousFirstResponder }.first
    }
}

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 nextno es necesariamente ella misma). Con esto podemos encontrarlo desde cualquier punto de vista, incluido UIWindow.

Y finalmente, podemos construir esto:

extension UIResponder {
    static var first: UIResponder? {
        return UIApplication.shared.windows.compactMap({ $0.previousFirstResponder }).first
    }
}

Entonces, cuando desee recuperar el primer respondedor, puede llamar a:

let firstResponder = UIResponder.first

0

La forma más sencilla de encontrar el primer respondedor:

func sendAction(_ action: Selector, to target: Any?, from sender: Any?, for event: UIEvent?) -> Bool

La implementación predeterminada distribuye el método de acción al objeto de destino dado o, si no se especifica ningún objetivo, al primer respondedor.

Próximo paso:

extension UIResponder
{
    private weak static var first: UIResponder? = nil

    @objc
    private func firstResponderWhereYouAre(sender: AnyObject)
    {
        UIResponder.first = self
    }

    static var actualFirst: UIResponder?
    {
        UIApplication.shared.sendAction(#selector(findFirstResponder(sender:)), to: nil, from: nil, for: nil)
        return UIResponder.first
    }
}

Uso: solo obténgalo UIResponder.actualFirstpara sus propios fines.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.