我正在设计一个自定义的通用警报视图,如下所示:
警报视图截屏
但是,此视图中的2个按钮始终执行相同的操作。
它始终对两个按钮执行下面的第二行代码。
optionAlertVC.btn_ok.actionHandle(controlEvents: .touchUpInside, ForAction: ok)
optionAlertVC.btn_cancel.actionHandle(controlEvents: .touchUpInside, ForAction: cancel)
显示一些代码来帮助我解决此问题。
ViewController:
func logout() {
AlertManager.shared.showAlertWithTwoOptions(viewController: self, message: "Confirm to logout?", okTitle: "Log out", dismissTitle: "Cancel", ok: {
self.gotoLogin()
}, cancel: {
//nothing to do
}, title: "Logout")
}
AlertManager:
typealias ok = () -> Void
typealias cancel = () -> Void
func showAlertWithTwoOptions(viewController: UIViewController, message: String, okTitle: String, dismissTitle:String, ok: @escaping ok , cancel: @escaping cancel, title:String? = nil) {
guard let optionAlertVC = Bundle.main.loadNibNamed("AlertView", owner: nil, options: nil)?[1] as? OptionAlertVC else {
print("error in loading error alert")
return
}
optionAlertVC.lbl_title.text = title ?? "Warning"
optionAlertVC.lbl_message.text = message
optionAlertVC.iv_icon.image = UIImage(named: "icon_warning")
optionAlertVC.btn_ok.backgroundColor = UIColor.MyTheme.greenSuccess
optionAlertVC.btn_ok.setTitle(okTitle, for: .normal)
optionAlertVC.btn_ok.titleLabel!.adjustsFontSizeToFitWidth = true
optionAlertVC.btn_cancel.backgroundColor = UIColor.MyTheme.redWarning
optionAlertVC.btn_cancel.setTitle(dismissTitle, for: .normal)
optionAlertVC.btn_cancel.titleLabel!.adjustsFontSizeToFitWidth = true
optionAlertVC.btn_cancel.titleLabel?.numberOfLines = 1
optionAlertVC.btn_ok.actionHandle(controlEvents: .touchUpInside, ForAction: ok)
optionAlertVC.btn_cancel.actionHandle(controlEvents: .touchUpInside, ForAction: cancel)
viewController.present(optionAlertVC, animated: true, completion: nil)
}
UIButtonExtension:
extension UIButton {
fileprivate func actionHandleBlock(action:(() -> Void)? = nil) {
struct __ {
static var action :(() -> Void)?
}
if action != nil {
__.action = action
} else {
__.action?()
}
}
@objc private func triggerActionHandleBlock() {
self.actionHandleBlock()
}
func actionHandle(controlEvents control :UIControl.Event, ForAction action:@escaping () -> Void) {
self.actionHandleBlock(action: action)
self.addTarget(self, action: #selector(UIButton.triggerActionHandleBlock), for: control)
}
}
答案 0 :(得分:1)
首先,您不应以这种方式处理button
触摸。其次,您对struct
的命名不正确。如果我不得不对struct
说些什么,那么我该如何命名,以便您知道我在谈论那个struct
?
涉及到实际问题,当您使用static
处理某些内容时,这变得有些棘手。当您在static
上声明action
变量static var action :(() -> Void)?
(即struct ___
)时,无论您有多少个按钮,它都会始终调用最新的按钮回调(即, closure
),因为它不是一个array
,它可以保留所有按钮的回调操作,它只是一个变量,因此它将继续用最新的button
覆盖以前的回调。我相信您应该删除UIButton
的扩展实现,因为它将继续引起不必要的问题。
实际上,您无需执行任何其他操作即可处理UIButton
触摸。只需为每个按钮声明一个单独的方法,并在添加目标时将其告知按钮,如下所示,
class OptionAlertVC: UIViewController {
var btn_ok: UIButton!
var btn_cancel: UIButton!
public var okCallback: (() -> Void)?
public var cancelCallback: (() -> Void)?
override func viewDidLoad() {
super.viewDidLoad()
btn_ok.addTarget(self, action: #selector(okAction), for: .touchUpInside)
btn_cancel.addTarget(self, action: #selector(cancelAction), for: .touchUpInside)
}
@objc func okAction() {
okCallback?()
}
@objc func cancelAction() {
cancelCallback?()
}
}
现在,在showAlertWithTwoOptions
中,您可以删除以下几行,
optionAlertVC.btn_ok.actionHandle(controlEvents: .touchUpInside, ForAction: ok)
optionAlertVC.btn_cancel.actionHandle(controlEvents: .touchUpInside, ForAction: cancel)
相反,将回调设置为此,
optionAlertVC.okCallback = ok
optionAlertVC.cancelCallback = cancel