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.
Peter Steinberger just tweeted about the private notification
UIWindowFirstResponderDidChangeNotification
, which you can observe if you want to watch the firstResponder change.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
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.
It's not pretty, but the way I resign the firstResponder when I don't know what that the responder is:
Create an UITextField, either in IB or programmatically. Make it Hidden. Link it up to your code if you made it in IB.
Then, when you want to dismiss the keyboard, you switch the responder to the invisible text field, and immediately resign it:
Iterate over the views that could be the first responder and use
- (BOOL)isFirstResponder
to determine if they currently are.If you just need to kill the keyboard when the user taps on a background area why not add a gesture recognizer and use it to send the
[[self view] endEditing:YES]
message?you can add the Tap gesture recogniser in the xib or storyboard file and connect it to an action,
looks something like this then finished
Here is a Extension implemented in Swift based on Jakob Egger's most excellent answer:
Swift 4