Search code examples
iosswiftuibuttonaddtarget

Adding a closure as target to a UIButton


I have a generic control class which needs to set the completion of the button depending on the view controller.Due to that setLeftButtonActionWithClosure function needs to take as parameter a closure which should be set as action to an unbutton.How would it be possible in Swift since we need to pass the function name as String to action: parameter.

func setLeftButtonActionWithClosure(completion: () -> Void)
{
    self.leftButton.addTarget(<#target: AnyObject?#>, action: <#Selector#>, forControlEvents: <#UIControlEvents#>)
}

Solution

  • Do Not Use This Answer, See Note Below

    NOTE: like @EthanHuang said "This solution doesn't work if you have more than two instances. All actions will be overwrite by the last assignment." Keep in mind this when you develop, i will post another solution soon.

    If you want to add a closure as target to a UIButton, you must add a function to UIButton class by using extension

    Swift 5

    import UIKit    
    extension UIButton {
        private func actionHandler(action:(() -> Void)? = nil) {
            struct __ { static var action :(() -> Void)? }
            if action != nil { __.action = action }
            else { __.action?() }
        }   
        @objc private func triggerActionHandler() {
            self.actionHandler()
        }   
        func actionHandler(controlEvents control :UIControl.Event, ForAction action:@escaping () -> Void) {
            self.actionHandler(action: action)
            self.addTarget(self, action: #selector(triggerActionHandler), for: control)
        }
    }
    

    Older

    import UIKit
    
    extension UIButton {
        private 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 :UIControlEvents, ForAction action:() -> Void) {
            self.actionHandleBlock(action)
            self.addTarget(self, action: "triggerActionHandleBlock", forControlEvents: control)
        }
    }
    

    and the call:

     let button = UIButton()
     button.actionHandle(controlEvents: .touchUpInside, 
     ForAction:{() -> Void in
         print("Touch")
     })