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#>) }
Using a UIControl with a closure callback viewDidLoad() let button = UIButton(type: . system) button. addTarget(self, action: #selector(buttonTapped(_:)), for: . touchUpInside) } @IBAction func buttonTapped(_ sender: UIButton) { print("Button tapped!") } }
In Swift, a closure is a special type of function without the function name. For example, { print("Hello World") } Here, we have created a closure that prints Hello World . Before you learn about closures, make sure to know about Swift Functions.
@IBAction is similar to @IBOutlet , but goes the other way: @IBOutlet is a way of connecting code to storyboard layouts, and @IBAction is a way of making storyboard layouts trigger code. This method takes one parameter, called sender . It's of type UIButton because we know that's what will be calling the method.
SwiftUI's button is similar to UIButton , except it's more flexible in terms of what content it shows and it uses a closure for its action rather than the old target/action system. To create a button with a string title you would start with code like this: Button("Button title") { print("Button tapped!") }
With iOS 14 Apple has finally added this feature to UIKit. However, someone might still want to use this extension because Apple's method signature is suboptimal.
iOS 14:
extension UIControl { func addAction(for controlEvents: UIControl.Event = .touchUpInside, _ closure: @escaping()->()) { addAction(UIAction { (action: UIAction) in closure() }, for: controlEvents) } }
pre-iOS 14:
extension UIControl { func addAction(for controlEvents: UIControl.Event = .touchUpInside, _ closure: @escaping()->()) { @objc class ClosureSleeve: NSObject { let closure:()->() init(_ closure: @escaping()->()) { self.closure = closure } @objc func invoke() { closure() } } let sleeve = ClosureSleeve(closure) addTarget(sleeve, action: #selector(ClosureSleeve.invoke), for: controlEvents) objc_setAssociatedObject(self, "\(UUID())", sleeve, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN) } }
Usage:
button.addAction { print("Hello, Closure!") }
or:
button.addAction(for: .touchUpInside) { print("Hello, Closure!") }
or if avoiding retain loops:
self.button.addAction(for: .touchUpInside) { [unowned self] in self.doStuff() }
(Extension is included here: https://github.com/aepryus/Acheron)
Also note, in theory .primaryActionTriggered could replace .touchUpInside, but it seems to be currently bugged in catalyst, so I'll leave it as is for now.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With