IOS Swift - How to assign a default action to all buttons programmatically

I work with the application at the prototype development stage. Some interface elements do not have any actions assigned to them either through the storyboard or programmatically.

In accordance with the recommendations of UX, I want to find these "inactive" buttons in the application and show them the warning "function is not available" when used during testing. Can this be done using the UIButton extension?

How can I assign a default UIButton action to display a warning if another assignment is not assigned through the interface builder or programmatically?

+6
source share
4

, , . , UIViewController , . , .

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        self.checkButtonAction()
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)

    }
    @IBAction func btn_Action(_ sender: UIButton) {

    }

}

extension UIViewController{
    func checkButtonAction(){
        for view in self.view.subviews as [UIView] {
            if let btn = view as? UIButton {
                if (btn.allTargets.isEmpty){
                    btn.add(for: .touchUpInside, {
                        let alert = UIAlertController(title: "Test 3", message:"No selector", preferredStyle: UIAlertControllerStyle.alert)

                        // add an action (button)
                        alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.default, handler: nil))

                        // show the alert
                        self.present(alert, animated: true, completion: nil)
                    })
                }
            }
        }

    }
}
class ClosureSleeve {
    let closure: ()->()

    init (_ closure: @escaping ()->()) {
        self.closure = closure
    }

    @objc func invoke () {
        closure()
    }
}

extension UIControl {
    func add (for controlEvents: UIControlEvents, _ closure: @escaping ()->()) {
        let sleeve = ClosureSleeve(closure)
        addTarget(sleeve, action: #selector(ClosureSleeve.invoke), for: controlEvents)
        objc_setAssociatedObject(self, String(format: "[%d]", arc4random()), sleeve, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN)
    }
}

. . .

+6

, :
1. - , , , , ,
2. swizzling - , .. init

+4

UIButton, , ?

swizzling:

swizzling , () , .

https://www.uraimo.com/2015/10/23/effective-method-swizzling-with-swift/

. .

- :

class ViewController: UIViewController {
    // MARK:- IBOutlets
    @IBOutlet weak var lblMessage: UILabel!

    // MARK:- IBActions
    @IBAction func applySwizzlingTapped(_ sender: Any) {
        swizzleButtonAction()
    }

    @IBAction func buttonTapped(_ sender: Any) {
        print("Original!")
        lblMessage.text = "Original!"
    }
}

extension ViewController {
    func swizzleButtonAction() {
        let originalSelector = #selector(buttonTapped(_:))
        let swizzledSelector = #selector(swizzledAction(_:))

        let originalMethod = class_getInstanceMethod(ViewController.self, originalSelector)
        let swizzledMethod = class_getInstanceMethod(ViewController.self, swizzledSelector)

        method_exchangeImplementations(originalMethod, swizzledMethod)
    }

    func swizzledAction(_ sender: Any) {
        print("Swizzled!")
        lblMessage.text = "Swizzled!"
    }
}

swizzleButtonAction(), " Swizzling" (applySwizzlingTapped) -, "Button" buttonTapped swizzledAction.


:

enter image description here

+1

I would implement this function using the IBOutlet collection variable, and then remove the buttons from this collection as soon as the function is implemented. something like that:

class ViewController {
    @IBOutlet var inactiveBtns: [UIButton]!

    func viewDidLoad() {
        inactiveBtns.forEach { (button) in
           button.addTarget(self, action: #selector(showDialog), for: UIControlEvents())
        }
    }

    func showDialog() {
        // show the dialog
    }
}

This IBOutlet is displayed in the interface builder, so you can add several buttons there.

0
source

All Articles