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

Swift5向其他类传递Selector实现UIAlertAction点击响应问题求助

问题原因与解决方案

核心错误点

  • 你在UIAlertAction的handler闭包内仅书写了actionAct1/actionAct2两个Selector变量,没有实际执行调用逻辑,因此触发「Selector未使用」警告,点击按钮自然没有响应。Selector需要绑定到目标对象调用才会执行对应方法。
  • 额外错误:你当前给popover?.sourceView赋值时错误将UIViewController类型的originVC强转为UIView,此处取值必然为nil,iPad端运行时弹窗会直接崩溃。
  • 补充注意:你在控制器中定义的restoreDefaults()方法需要添加@objc标记,否则Selector调用时会因为找不到方法抛出运行时异常。

修正后的AlertGenFromVC代码

class AlertGenFromVC {
    // 直接限定为VC类型,避免后续强转错误,用weak避免循环引用
    weak var originVC: UIViewController? 
    var originTextField: UITextField?
    
    init(sendingVC: UIViewController) {
         originVC = sendingVC
    }
    
    func generateAlert(titleIn: String, messageIn: String, actionTitle1:String, actionAct1:Selector, actionTitle2:String?, actionAct2:Selector?) -> UIAlertController {
        let alert = UIAlertController(
            title: titleIn,
            message: messageIn,
            preferredStyle: .alert)
        
        // 修正Action1的执行逻辑
        let action1 = UIAlertAction(title: actionTitle1, style: .default, handler: { [weak self] _ in
            guard let self = self, let target = self.originVC else { return }
            target.perform(actionAct1)
        })
        alert.addAction(action1)
        
        if let actionTitle2 = actionTitle2 {
            if let actionAct2 = actionAct2 {
                // 修正Action2的执行逻辑
                let action2 = UIAlertAction(title: actionTitle2, style: .default, handler: { [weak self] _ in
                    guard let self = self, let target = self.originVC else { return }
                    target.perform(actionAct2)
                })
                alert.addAction(action2)
            } else {
                let action2 = UIAlertAction(title: actionTitle2, style: .default, handler: nil)
                alert.addAction(action2)
            }
        }
        
        let popover = alert.popoverPresentationController
        // 修正sourceView取值
        popover?.sourceView = self.originVC?.view
        popover?.sourceRect = CGRect(x: 32, y: 32, width: 64, height: 64)
        return alert
    }
}

你控制器中的restoreDefaults方法要加上@objc标记:

@objc func restoreDefaults() {
    // 原有逻辑保持不变
}

更优的Swift风格改造建议

Selector依赖OC runtime,存在方法名称写错/未加@objc就会崩溃的风险,你可以把参数替换为闭包类型,使用更安全:

// 修改后的generateAlert方法签名
func generateAlert(titleIn: String, 
                   messageIn: String,
                   actionTitle1:String, 
                   action1Handler: @escaping () -> Void,
                   actionTitle2:String?, 
                   action2Handler: (() -> Void)?) -> UIAlertController {
    // 创建Action时直接调用闭包即可
    let action1 = UIAlertAction(title: actionTitle1, style: .default, handler: { _ in
        action1Handler()
    })
    // 其余逻辑和上述修正版一致,调用处直接传对应执行逻辑即可,无需再加@objc标记
}

调用示例:

let alert = AlertGenFromVC(sendingVC: self).generateAlert(
    titleIn: "Warning!",
    messageIn: "You are about to reset to the default settings. You will not be able to undo this action.",
    actionTitle1: "Reset",
    action1Handler: { [weak self] in self?.restoreDefaults() },
    actionTitle2: "Cancel",
    action2Handler: nil)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.03 21:57:05