Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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#>) } 
like image 407
Ilker Baltaci Avatar asked Sep 18 '14 18:09

Ilker Baltaci


People also ask

How do I add a target to UIButton?

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!") } }

What is closure Swift?

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.

What is IBOutlet and IBAction in Swift?

@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.

How do I make a button in SwiftUI?

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!") }


1 Answers

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.

like image 173
aepryus Avatar answered Sep 21 '22 18:09

aepryus