Skip to main content
AI Assist is now on Stack Overflow. Start a chat to get instant answers from across the network. Sign up to save and share your chats.
Linking to gists with better implementations. Explaining more extensively why the pros and cons of each method.
Source Link
vilanovi
  • 2.1k
  • 2
  • 21
  • 25

You must not forget about UIViewControllersThe first responder can be any instance of the class UIResponder, so there are other classes that maymight be asthe first responder despite the UIViews. For example UIViewController might also be the FirstResponderfirst responder.

For that reason,In this gist you may loop intowill find a recursive way to get the UIViewController hierarchy, as well as intofirst responder by looping through the UIView hierarchy of controllers starting from the rootViewController of the application's windows.

You can retrieve then the first responder by doing

@implementation UIView (FindFirstResponder) - (UIView *)findFirstResponder { if (self.isFirstResponder) { return self; } for (UIView *subView in self.subviews) { UIView *firstResponder = [subView findFirstResponder]; if (firstResponder != nil) { return firstResponder; } } return nil; } @end @implementation UIViewController (FindFirstResponder) - (idvoid)findFirstResponder {foo  if (self.isFirstResponder) {    return self; // Get the first } responder id firstResponder = [self.view findFirstResponder]; if (firstResponder != nil) { return firstResponder; } for (UIViewController *childViewController in self.childViewControllers) {  firstResponder = [childViewController[UIResponder findFirstResponder];firstResponder];     if (firstResponder != nil) { // Do whatever returnyou firstResponder;want   }  [firstResponder resignFirstResponder]; }  return nil; }   @end 

SoHowever, nowif the first responder is not a subclass of UIView or UIViewController, in your method youthis approach will fail.

To fix this problem we can do a different approach by creating a category on UIResponder and perform some magic swizzeling to be able to build an array of all living instances of this class. Then, to get the first responder simply by doing:we can simple iterate and ask each object if -isFirstResponder.

- (void)foo { UIWindow *mainWindow = [[UIApplication sharedApplication] keyWindow]; UIResponder *firstResponder = [mainWindow.rootViewController findFirstResponder]; // Do what you want with your firstResponder } 

This approach can be found implemented in this other gist.

Hope it helps.

You must not forget about UIViewControllers, that may be as UIViews the FirstResponder.

For that reason, you may loop into the UIViewController hierarchy, as well as into the UIView hierarchy.

@implementation UIView (FindFirstResponder) - (UIView *)findFirstResponder { if (self.isFirstResponder) { return self; } for (UIView *subView in self.subviews) { UIView *firstResponder = [subView findFirstResponder]; if (firstResponder != nil) { return firstResponder; } } return nil; } @end @implementation UIViewController (FindFirstResponder) - (id)findFirstResponder {  if (self.isFirstResponder) {    return self;  }  id firstResponder = [self.view findFirstResponder]; if (firstResponder != nil) { return firstResponder; } for (UIViewController *childViewController in self.childViewControllers) {  firstResponder = [childViewController findFirstResponder];     if (firstResponder != nil) {  return firstResponder;   }  }  return nil; }   @end 

So, now, in your method you can get the first responder simply by doing:

- (void)foo { UIWindow *mainWindow = [[UIApplication sharedApplication] keyWindow]; UIResponder *firstResponder = [mainWindow.rootViewController findFirstResponder]; // Do what you want with your firstResponder } 

The first responder can be any instance of the class UIResponder, so there are other classes that might be the first responder despite the UIViews. For example UIViewController might also be the first responder.

In this gist you will find a recursive way to get the first responder by looping through the hierarchy of controllers starting from the rootViewController of the application's windows.

You can retrieve then the first responder by doing

- (void)foo { // Get the first responder id firstResponder = [UIResponder firstResponder]; // Do whatever you want [firstResponder resignFirstResponder]; } 

However, if the first responder is not a subclass of UIView or UIViewController, this approach will fail.

To fix this problem we can do a different approach by creating a category on UIResponder and perform some magic swizzeling to be able to build an array of all living instances of this class. Then, to get the first responder we can simple iterate and ask each object if -isFirstResponder.

This approach can be found implemented in this other gist.

Hope it helps.

Source Link
vilanovi
  • 2.1k
  • 2
  • 21
  • 25

You must not forget about UIViewControllers, that may be as UIViews the FirstResponder.

For that reason, you may loop into the UIViewController hierarchy, as well as into the UIView hierarchy.

@implementation UIView (FindFirstResponder) - (UIView *)findFirstResponder { if (self.isFirstResponder) { return self; } for (UIView *subView in self.subviews) { UIView *firstResponder = [subView findFirstResponder]; if (firstResponder != nil) { return firstResponder; } } return nil; } @end @implementation UIViewController (FindFirstResponder) - (id)findFirstResponder { if (self.isFirstResponder) { return self; } id firstResponder = [self.view findFirstResponder]; if (firstResponder != nil) { return firstResponder; } for (UIViewController *childViewController in self.childViewControllers) { firstResponder = [childViewController findFirstResponder]; if (firstResponder != nil) { return firstResponder; } } return nil; } @end 

So, now, in your method you can get the first responder simply by doing:

- (void)foo { UIWindow *mainWindow = [[UIApplication sharedApplication] keyWindow]; UIResponder *firstResponder = [mainWindow.rootViewController findFirstResponder]; // Do what you want with your firstResponder }