I had this problem with iOS / UIWebView
, which doesn't implement makeFirstResponder
in UIWindow
, nor webViewDidEndEditing
or shouldBeginEditingInDOMRange
. However, with the use of Swizzling I was able to create a helper category that allows for retrieval of the current first responder, as well as posting a notification every time first responder changes. Really frustrating how all this should be public API, but isn't, as swizzle isn't normally a first goto, but this worked well enough.
First, setup your category header:
@interface UIResponder (Swizzle)
+ (UIResponder *)currentFirstResponder;
- (BOOL)customBecomeFirstResponder;
@end
Then Category implementation
@implementation UIResponder (Swizzle)
// It's insanity that there is no better way to get a notification when the first responder changes, but there it is.
static UIResponder *sCurrentFirstResponder;
+ (UIResponder *)currentFirstResponder {
return sCurrentFirstResponder;
}
- (BOOL)customBecomeFirstResponder {
NSMutableDictionary *userInfo = [NSMutableDictionary dictionaryWithCapacity:2];
if(sCurrentFirstResponder) {
[userInfo setObject:sCurrentFirstResponder forKey:NSKeyValueChangeOldKey];
}
sCurrentFirstResponder = self;
if(sCurrentFirstResponder) {
[userInfo setObject:sCurrentFirstResponder forKey:NSKeyValueChangeNewKey];
}
[[NSNotificationCenter defaultCenter] postNotificationName:kFirstResponderDidChangeNotification
object:nil
userInfo:userInfo];
return [self customBecomeFirstResponder];
}
@end
Finally, using a helper like JR Swizzle, swap the classes.
#import "JRSwizzle.h"
- (void)applicationLoaded {
if(![UIResponder jr_swizzleMethod:@selector(becomeFirstResponder) withMethod:@selector(customBecomeFirstResponder) error:&error]) {
NSLog(@"Error swizzling - %@",error);
}
}
Thought I'd share. Valid in App store as it doesn't utilize private API, and while Apple cautions against swizzling base classes there is no edict against doing so.