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
相关产品推荐
相关产品推荐

