Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there any way of asking an iOS view which of its children has first responder status? [duplicate]

In Mac OS X, you can find the first responder like this:

[[self window] firstResponder] 

Is there any way of doing it in iOS? Or do you need to enumerate the child controls and send an isFirstRespondermessage to each one?

like image 276
Tommy Herbert Avatar asked Feb 17 '11 13:02

Tommy Herbert


People also ask

What is IOS first responder?

The first responder is usually the first object in a responder chain to receive an event or action message. In most cases, the first responder is a view object that the user selects or activates with the mouse or keyboard.

What is UIResponder in IOS?

An abstract interface for responding to and handling events.

What is the responder chain?

The responder chain is the series of events that happen once we start interacting with the application on the iPhone. As an example, whenever we tap on an UITextfield, the whole series of responder initiates. It happens because of elements like UIView, UIViewController, UIApplication subclass UIResponder.

What is First Responder UIKit?

Determining an Event's First Responder UIKit designates an object as the first responder to an event based on the type of that event. Event types include: Event type. First responder. Touch events.


2 Answers

I really like VJK's solution, but as MattDiPasquale suggests it seems more complex than necessary. So I wrote this simpler version:

Objective-C

UIResponder+FirstResponder.h:

#import <UIKit/UIKit.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 

Swift 4

import UIKit  extension UIResponder {      private static weak var _currentFirstResponder: UIResponder?      static var currentFirstResponder: UIResponder? {         _currentFirstResponder = nil         UIApplication.shared.sendAction(#selector(UIResponder.findFirstResponder(_:)), to: nil, from: nil, for: nil)          return _currentFirstResponder     }      @objc func findFirstResponder(_ sender: Any) {         UIResponder._currentFirstResponder = self     } } 

I also made it a class method since that seemed to make more sense. You can now find the first responder like so: [UIResponder currentFirstResponder]


like image 121
Jakob Egger Avatar answered Sep 18 '22 15:09

Jakob Egger


I wrote a category on UIResponder to find the first responder

@interface UIResponder (firstResponder) - (id) currentFirstResponder; @end 

and

#import <objc/runtime.h> #import "UIResponder+firstResponder.h"  static char const * const aKey = "first";  @implementation UIResponder (firstResponder)  - (id) currentFirstResponder {     [[UIApplication sharedApplication] sendAction:@selector(findFirstResponder:) to:nil from:self forEvent:nil];     id obj = objc_getAssociatedObject (self, aKey);     objc_setAssociatedObject (self, aKey, nil, OBJC_ASSOCIATION_ASSIGN);     return obj; }  - (void) setCurrentFirstResponder:(id) aResponder {     objc_setAssociatedObject (self, aKey, aResponder, OBJC_ASSOCIATION_ASSIGN); }  - (void) findFirstResponder:(id) sender {     [sender setCurrentFirstResponder:self]; }  @end 

Then in any class that derives from a UIResponder you can get the first responder by calling

UIResponder* aFirstResponder = [self currentFirstResponder]; 

but remember to import the UIResponder category interface file first!

This uses documented API's so there should be no app store rejection issues.

like image 36
VJK Avatar answered Sep 16 '22 15:09

VJK