0

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.

Eddwin Paz
  • 2,842
  • 4
  • 28
  • 48
  • Check Interface Builder. May be you connected the button with view controller, then removed the code from view controller, but missed the connection. – Alexander Volkov Sep 09 '19 at 18:22
  • @AlexanderVolkov I'm not using storyboard. It's all by code. – Eddwin Paz Sep 09 '19 at 18:25
  • It looks like the target is the view? You'll need to either set the target of the action as the view controller, or set up a path so the view can convey the action to the view controller (for example, via delegation). – Joshua Kaden Sep 09 '19 at 18:44
  • @3ddpaz then check where your code is. Looks like `self` is targeting the view controller. Change it to your view there you have `optionClicked` method. – Alexander Volkov Sep 09 '19 at 18:48
  • @AlexanderVolkov Added the self from uiviewcontroller as delegate to uiview and added it to self on addTarget nothing happened. – Eddwin Paz Sep 09 '19 at 19:06
  • @JoshuaKaden Tried it and nothing so far. – Eddwin Paz Sep 09 '19 at 19:06
  • @3ddpaz Please show the whole code. I don't understand what `Added the self from uiviewcontroller as delegate` means. You should do something like that `button.addTarget(, action: #selector(optionClicked(_:)), for: .touchUpInside)` – Alexander Volkov Sep 09 '19 at 19:23
  • @AlexanderVolkov I get Use of unresolved identifier 'optionClicked' when passing var controller: UIViewController! from UIviewController. as shareView.controller = self – Eddwin Paz Sep 09 '19 at 19:26
  • @3ddpaz check the asnwer just added by Jakub Skořepa . It's correct. – Alexander Volkov Sep 09 '19 at 19:33
  • @AlexanderVolkov Yeah I tried it in a different way and worked out. – Eddwin Paz Sep 09 '19 at 19:37

1 Answers1

2

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!

Jakub Skořepa
  • 244
  • 3
  • 8
  • Tried implementing your solution But I get this. Value of type 'DrawerController' has no member 'optionClicked' – Eddwin Paz Sep 09 '19 at 19:32
  • @3ddpaz I have just implemented it and it's working fine for me. Can you try to clean the project `Product > Clean build folder` and restart Xcode if it doesn't help? I don't see any issue with the code itself, are you using any access modifiers like `private` or `fileprivate`? – Jakub Skořepa Sep 09 '19 at 19:41