2

I would like to pass a function as parameter, and use it in the UITableView extension. In the function named 'setEmptyView', I made UIButton programmatically, and added some target action. Here's what I've done so far.

extension UITableView {
    func setEmptyView(message: String, actionButtonClosure: @escaping () -> Void) {
        let emptyView = UIView()
        let messageLabel = UILabel()
        let button = UIButton()

        // adding subview and making constraints codes....

        button.addTarget(self, action: #selector(buttonAction(_:)), for: .touchUpInside)
    }
    @objc func buttonAction (_ sender: UIButton!) {
        actionButtonClosure()    <---- error
    }
}

class ViewController: UITableViewDataSource, UITableViewDelegate {
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        if count == 0 {
            let message = "Here is placeholder for this table"
            tableView.setEmptyView(message: message, buttonTitle: "see more") { [self] in
                goToMenu()
            }
        }
        return count
    }
    func goToMenu() {
        // move to next VC
    }

Unfortunately 'actionButtonClosure' function in parameter cannot be accessible because it's two different function. I also tried .addAction() to the button, but it is only available since iOS14. What would you suggest to do here? How can I pass function parameter and use it as button action?

haledev
  • 21
  • 1
  • "cannot be accessible because it's two different function" Correct. You would need to store the action button closure somewhere that the action method can see it and call it. – matt Mar 20 '21 at 22:24
  • 1
    Storing the closure somewhere seems cool, but I wanted to use it more dynamically. So I created an extension for UIButton which makes addAction() function manually. But thanks for your suggestions tho! – haledev Mar 21 '21 at 14:18

1 Answers1

0

It's not fancy at all my solution, but at least it can work.

Create a static var of type (() -> Void)? inside the extension. I will show you:

extension UITableView {

    static var buttonClosure: ( () -> Void)?

    func setEmptyView(message: String, actionButtonClosure: @escaping () -> Void) {
        let emptyView = UIView()
        let messageLabel = UILabel()
        let button = UIButton()

        // Assign the action to the var
        Self.buttonClosure = actionButtonClosure
 
        // adding subview and making constraints codes....

        button.addTarget(self, action: #selector(buttonAction(_:)), for: .touchUpInside)
    }
    @objc func buttonAction (_ sender: UIButton!) {

        // Safe unwrapped to avoid crashes
        if let closure = Self.buttonClosure {
           
           // Execute the function
           closure()

           // Uncomment the next line if you want avoid repeat the action more than one
           // Self.buttonClosure = nil
        }
    }
}

...

This can work to you. Best regards and happy coding

  • Static? Why is that a good idea? – matt Mar 21 '21 at 05:10
  • I never said it was the optimal version, in fact I said: *It's not fancy at all my solution* , But at least it is easy to read and understand the fact that for it to work you must save the reference to the closure so that later you can execute it – Julio César Arregoitía Val Mar 21 '21 at 05:18
  • In fact matt, I sent my post and then I saw your comment above where you explain that you should save the reference. My code is just a simple example of what you tried to explain in words. Haledev is Student at Chung-Ang University, for sure he(or she) can improve it. – Julio César Arregoitía Val Mar 21 '21 at 05:25
  • 1
    Using static works, but I wanted to pass the functions more dynamically, so I just created an extension for UIButton. Making addAction() function manually worked well. But thanks for your suggestions though! – haledev Mar 21 '21 at 14:22
  • Ok, I understand. I will help you with your reputation. Best regards. – Julio César Arregoitía Val Mar 21 '21 at 19:41