I submitted my app a little over a week ago and got the dreaded rejection email today. It tells me that my app cannot be accepted because I'm using a non-public API; specifically, it says,
The non-public API that is included in your application is firstResponder.
Now, the offending API call is actually a solution I found here on SO:
UIWindow *keyWindow = [[UIApplication sharedApplication] keyWindow];
UIView *firstResponder = [keyWindow performSelector:@selector(firstResponder)];
How do I get the current first responder on the screen? I'm looking for a way that won't get my app rejected.
The solution from romeo https://stackoverflow.com/a/2799675/661022 is cool, but I noticed that the code needs one more loop. I was working with tableViewController. I edited the script and then I checked. Everything worked perfect.
I recommed to try this:
Just it case here is Swift version of awesome Jakob Egger's approach:
Update: I was wrong. You can indeed use
UIApplication.shared.sendAction(_:to:from:for:)
to call the first responder demonstrated in this link: http://stackoverflow.com/a/14135456/746890.Most of the answers here can't really find the current first responder if it is not in the view hierarchy. For example,
AppDelegate
orUIViewController
subclasses.There is a way to guarantee you to find it even if the first responder object is not a
UIView
.First lets implement a reversed version of it, using the
next
property ofUIResponder
:With this computed property, we can find the current first responder from bottom to top even if it's not
UIView
. For example, from aview
to theUIViewController
who's managing it, if the view controller is the first responder.However, we still need a top-down resolution, a single
var
to get the current first responder.First with the view hierarchy:
This will search for the first responder backwards, and if it couldn't find it, it would tell its subviews to do the same thing (because its subview's
next
is not necessarily itself). With this we can find it from any view, includingUIWindow
.And finally, we can build this:
So when you want to retrieve the first responder, you can call:
A common way of manipulating the first responder is to use nil targeted actions. This is a way of sending an arbitrary message to the responder chain (starting with the first responder), and continuing down the chain until someone responds to the message (has implemented a method matching the selector).
For the case of dismissing the keyboard, this is the most effective way that will work no matter which window or view is first responder:
This should be more effective than even
[self.view.window endEditing:YES]
.(Thanks to BigZaphod for reminding me of the concept)
Here's a category that allows you to quickly find the first responder by calling
[UIResponder currentFirstResponder]
. Just add the following two files to your project:UIResponder+FirstResponder.h
UIResponder+FirstResponder.m
The trick here is that sending an action to nil sends it to the first responder.
(I originally published this answer here: https://stackoverflow.com/a/14135456/322427)
If your ultimate aim is just to resign the first responder, this should work:
[self.view endEditing:YES]