我在一个多星期前提交了应用,今天收到了可怕的拒绝邮件。它告诉我,我的应用程序不能被接受,因为我使用的是非公共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

其他回答

找到第一响应者的最简单方法:

func sendAction(_ action: Selector, to target: Any?, from sender: Any?, for event: UIEvent?) -> Bool

默认实现将动作方法分派给给定对象 目标对象,如果没有指定目标,则发送给第一个响应器。

下一步:

extension UIResponder
{
    private weak static var first: UIResponder? = nil

    @objc
    private func firstResponderWhereYouAre(sender: AnyObject)
    {
        UIResponder.first = self
    }

    static var actualFirst: UIResponder?
    {
        UIApplication.shared.sendAction(#selector(findFirstResponder(sender:)), to: nil, from: nil, for: nil)
        return UIResponder.first
    }
}

用法: 只需要获取UIResponder。首先是为了你自己的目的。

你也可以这样尝试:

- (void) touchesBegan: (NSSet *) touches withEvent: (UIEvent *) event { 

    for (id textField in self.view.subviews) {

        if ([textField isKindOfClass:[UITextField class]] && [textField isFirstResponder]) {
            [textField resignFirstResponder];
        }
    }
} 

我没有试过,但这似乎是个不错的解决办法

如果你的最终目标只是辞职第一个响应者,这应该工作:[self。视图endEditing:是的)

romeo https://stackoverflow.com/a/2799675/661022的解决方案很酷,但我注意到代码还需要一个循环。我在使用tableViewController。 我编辑了剧本,然后检查了一下。一切都很完美。

我建议你这样做:

- (void)findFirstResponder
{
    NSArray *subviews = [self.tableView subviews];
    for (id subv in subviews )
    {
        for (id cell in [subv subviews] ) {
            if ([cell isKindOfClass:[UITableViewCell class]])
            {
                UITableViewCell *aCell = cell;
                NSArray *cellContentViews = [[aCell contentView] subviews];
                for (id textField in cellContentViews)
                {
                    if ([textField isKindOfClass:[UITextField class]])
                    {
                        UITextField *theTextField = textField;
                        if ([theTextField isFirstResponder]) {
                            NSLog(@"current textField: %@", theTextField);
                            NSLog(@"current textFields's superview: %@", [theTextField superview]);
                        }
                    }
                }
            }
        }
    }
}

在UIResponder上有一个category,你可以合法地要求UIApplication对象告诉你谁是第一个responder。

看到这个:

有没有办法问一个iOS视图它的哪个子视图具有第一响应器状态?