我在一个多星期前提交了应用,今天收到了可怕的拒绝邮件。它告诉我,我的应用程序不能被接受,因为我使用的是非公共API;具体来说,它说,

应用程序中包含的非公共API是firstResponder。

现在,违规的API调用实际上是一个解决方案,我发现这里的SO:

UIWindow *keyWindow = [[UIApplication sharedApplication] keyWindow];
UIView   *firstResponder = [keyWindow performSelector:@selector(firstResponder)];

如何在屏幕上显示当前的第一响应器?我正在寻找一种不会让我的应用程序被拒绝的方法。


当前回答

操作第一响应器的常用方法是使用nil目标操作。这是一种向响应器链发送任意消息的方式(从第一个响应器开始),并沿着链继续向下,直到有人响应消息(已经实现了与选择器匹配的方法)。

对于取消键盘的情况,这是最有效的方法,无论哪个窗口或视图是第一响应器:

[[UIApplication sharedApplication] sendAction:@selector(resignFirstResponder) to:nil from:nil forEvent:nil];

这应该比[self.view]更有效。窗口endEditing:是的)。

(感谢BigZaphod提醒我这个概念)

其他回答

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

看到这个:

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

在我的一个应用程序中,如果用户在后台点击,我经常希望第一响应器辞职。为了这个目的,我在UIView上写了一个category,我在UIWindow上调用它。

下面的代码基于此,应该返回第一个响应器。

@implementation UIView (FindFirstResponder)
- (id)findFirstResponder
{
    if (self.isFirstResponder) {
        return self;        
    }
    for (UIView *subView in self.subviews) {
        id responder = [subView findFirstResponder];
        if (responder) return responder;
    }
    return nil;
}
@end

iOS 7 +

- (id)findFirstResponder
{
    if (self.isFirstResponder) {
        return self;
    }
    for (UIView *subView in self.view.subviews) {
        if ([subView isFirstResponder]) {
            return subView;
        }
    }
    return nil;
}

迅速:

extension UIView {
    var firstResponder: UIView? {
        guard !isFirstResponder else { return self }

        for subview in subviews {
            if let firstResponder = subview.firstResponder {
                return firstResponder
            }
        }

        return nil
    }
}

在Swift中的使用示例:

if let firstResponder = view.window?.firstResponder {
    // do something with `firstResponder`
}

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

下面是一个基于Jakob Egger最优秀的答案在Swift中实现的扩展:

import UIKit

extension UIResponder {
    // Swift 1.2 finally supports static vars!. If you use 1.1 see: 
    // http://stackoverflow.com/a/24924535/385979
    private weak static var _currentFirstResponder: UIResponder? = nil
    
    public class func currentFirstResponder() -> UIResponder? {
        UIResponder._currentFirstResponder = nil
        UIApplication.sharedApplication().sendAction("findFirstResponder:", to: nil, from: nil, forEvent: nil)
        return UIResponder._currentFirstResponder
    }
    
    internal func findFirstResponder(sender: AnyObject) {
        UIResponder._currentFirstResponder = self
    }
}

斯威夫特4

import UIKit    

extension UIResponder {
    private weak static var _currentFirstResponder: UIResponder? = nil
    
    public static var current: UIResponder? {
        UIResponder._currentFirstResponder = nil
        UIApplication.shared.sendAction(#selector(findFirstResponder(sender:)), to: nil, from: nil, for: nil)
        return UIResponder._currentFirstResponder
    }
    
    @objc internal func findFirstResponder(sender: AnyObject) {
        UIResponder._currentFirstResponder = self
    }
}

使用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。