Eddwin Paz
Eddwin Paz

Reputation: 2878

Dynamic Creation UIButton AddTarget on UIView executed on UIViewController

Currently this code that executes a Tag Styled List, The issue remains when I want to try to pass the addTarget Action optionClicked to my UIViewController

DrawerView.swift


let menuOptions = ["Info", "Actions", "Users", "Patiens"]

        menuOptions.forEach({

            let button = UIButton()
            button.setTitle($0, for: .normal)

            if $0.contains(menuOptions[0]) {
                button.style(with: .filled)
            } else {
                button.style(with: .outlined)
                button.addTarget(self, action: #selector(optionClicked(_:)), for: .touchUpInside)
            }
            actionStackView.addArrangedSubview(button)
        })

DrawerController.swift


class DrawerController: UIViewController {

    var shareView = DrawerView()
    var viewModel: CarDetailViewModel?

    override func loadView() {
        shareView.viewModel = viewModel
        view = shareView
    }

    @objc func optionClicked(_ sender: UIButton) {

        let feedbackGenerator = UISelectionFeedbackGenerator()
        feedbackGenerator.selectionChanged()

        let optionClicked: String = sender.titleLabel?.text ?? "0"

        switch optionClicked {
        case "Actions": present(DrawerActionController(), animated: true, completion: nil)
        case "Notifications":
            let viewController = DrawerNotificationController()
            viewController.carDetailViewModel = viewModel
           present(viewController, animated: true, completion: nil)

        case "Patients":
            let viewUserController = DrawerUserController()
            viewUserController.carPath = "9000"
           present(viewUserController, animated: true, completion: nil)
        default: break
        }
    }
}

Tried button.addTarget(self, action: #selector(optionClicked(_:)), for: .touchUpInside) but did not work out.

Upvotes: 0

Views: 946

Answers (1)

Jakub Skořepa
Jakub Skořepa

Reputation: 254

In the method button.addTarget(self, action: #selector(optionClicked(_:)), for: .touchUpInside) you need to provide pointer to the viewController which will receive the action.

The easiest way in your case would be to create lazy variable DrawerView with DrawerController on the init and use the drawer controller in the button action.

DrawerView.swift

class DrawerView: UIView {

    private unowned let drawerController: DrawerController

    init(drawerController: DrawerController) {
        self.drawerController = drawerController
    }

    ... wherever is your code placed ...

    let menuOptions = ["Info", "Actions", "Users", "Patiens"]

    menuOptions.forEach({

        let button = UIButton()
        button.setTitle($0, for: .normal)

        if $0.contains(menuOptions[0]) {
            button.style(with: .filled)
        } else {
            button.style(with: .outlined)
            button.addTarget(drawerController, action: #selector(DrawerController.optionClicked(_:)), for: .touchUpInside)
            actionStackView.addArrangedSubview(button)
        }
    })

    ....
}

It's important you use unowned or weak to prevent retain cycles and memory leaks

To create the DrawerView you can use a lazy variable:

lazy var shareView: DrawerView = DrawerView(drawerController: self)

lazy will allow you to use self, you can also use optional and create the variable later, but that's basically what lazy does.

Hope it helps!

Upvotes: 2

Related Questions