You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

iOS 11(Swift 4、Xcode 9.X)中First Responder缺失问题求助

搞定第一响应者检测的问题

兄弟,我之前也踩过类似的第一响应者检测坑,结合你说的无Storyboard精简App的情况,咱们一步步来排查解决:

1. 先搞懂核心:普通UIView默认不能当第一响应者

这大概率是你检测全返回false的原因——系统默认的UIView是没有成为第一响应者的权限的,得咱们手动开权限。

给你的topView(或者你想设为第一响应者的视图)重写canBecomeFirstResponder方法,返回true:

class TopView: UIView {
    // 允许这个视图成为第一响应者
    override var canBecomeFirstResponder: Bool {
        return true
    }
    
    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        super.touchesBegan(touches, with: event)
        // 现在再检测试试
        checkFirstResponderStatus()
    }
    
    private func checkFirstResponderStatus() {
        print("TopView 是否是第一响应者?\(isFirstResponder)")
        print("主视图 是否是第一响应者?\(superview?.isFirstResponder ?? false)")
        print("窗口 是否是第一响应者?\(UIApplication.shared.keyWindow?.isFirstResponder ?? false)")
    }
}

2. 主动让视图“上位”成第一响应者

光开权限还不够,得在合适的时机让它主动成为第一响应者,比如视图加载完成后:

class ViewController: UIViewController {
    var topView: TopView!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        setupTopView()
        // 用异步确保视图已经完成布局,再调用成为第一响应者的方法
        DispatchQueue.main.async {
            self.topView.becomeFirstResponder()
        }
    }
    
    private func setupTopView() {
        topView = TopView(frame: CGRect(x: 0, y: 100, width: view.frame.width, height: 100))
        topView.backgroundColor = .orange
        view.addSubview(topView)
    }
}

3. 换个姿势获取触摸对应的响应者

如果还是有问题,你可以直接从触摸事件里拿到触发触摸的视图,看看它的第一响应者状态:

override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
    super.touchesBegan(touches, with: event)
    guard let touch = touches.first, let touchedView = touch.view else { return }
    print("当前触摸的视图:\(touchedView)")
    print("这个视图是第一响应者吗?\(touchedView.isFirstResponder)")
}

4. 排查响应链的特殊情况

你说这不是简单的视图层级,那得留意有没有自定义容器视图(比如UIScrollView子类、自定义导航容器)干扰了响应链。可以给UIResponder加个扩展,跟踪第一响应者的变化日志:

extension UIResponder {
    override open func becomeFirstResponder() -> Bool {
        print("\(self) 成为了第一响应者")
        return super.becomeFirstResponder()
    }
    
    override open func resignFirstResponder() -> Bool {
        print("\(self) 退出了第一响应者")
        return super.resignFirstResponder()
    }
}

这样你就能清晰看到哪个对象在什么时候切换第一响应者状态,快速定位问题出在哪。


内容的提问来源于stack exchange,提问作者eharo2

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.19 09:57:07