我在一个多星期前提交了应用,今天收到了可怕的拒绝邮件。它告诉我,我的应用程序不能被接受,因为我使用的是非公共API;具体来说,它说,
应用程序中包含的非公共API是firstResponder。
现在,违规的API调用实际上是一个解决方案,我发现这里的SO:
UIWindow *keyWindow = [[UIApplication sharedApplication] keyWindow];
UIView *firstResponder = [keyWindow performSelector:@selector(firstResponder)];
如何在屏幕上显示当前的第一响应器?我正在寻找一种不会让我的应用程序被拒绝的方法。
下面是一个报告正确的第一响应器的解决方案(例如,许多其他解决方案不会报告UIViewController作为第一响应器),不需要在视图层次结构上循环,也不使用私有api。
它利用了苹果的sendAction:to:from:forEvent:方法,该方法已经知道如何访问第一个响应器。
我们只需要在2个方面进行调整:
扩展UIResponder,这样它就可以在第一个responder上执行我们自己的代码。
子类UIEvent来返回第一个响应器。
代码如下:
@interface ABCFirstResponderEvent : UIEvent
@property (nonatomic, strong) UIResponder *firstResponder;
@end
@implementation ABCFirstResponderEvent
@end
@implementation UIResponder (ABCFirstResponder)
- (void)abc_findFirstResponder:(id)sender event:(ABCFirstResponderEvent *)event {
event.firstResponder = self;
}
@end
@implementation ViewController
+ (UIResponder *)firstResponder {
ABCFirstResponderEvent *event = [ABCFirstResponderEvent new];
[[UIApplication sharedApplication] sendAction:@selector(abc_findFirstResponder:event:) to:nil from:nil forEvent:event];
return event.firstResponder;
}
@end
使用Swift和一个特定的UIView对象,这可能会有所帮助:
func findFirstResponder(inView view: UIView) -> UIView? {
for subView in view.subviews as! [UIView] {
if subView.isFirstResponder() {
return subView
}
if let recursiveSubView = self.findFirstResponder(inView: subView) {
return recursiveSubView
}
}
return nil
}
只需要把它放在你的UIViewController中,然后像这样使用它:
let firstResponder = self.findFirstResponder(inView: self.view)
请注意,结果是一个可选值,所以如果在给定的视图子视图层次结构中没有找到firstResponder,它将为nil。