valeriana
valeriana

Reputation: 159

iOS - Swift . MVC to MVVM refactor. Use Delegate method to handle IBActions

Using storyboard to build UI.

Swift 5.

My setup is as follows :

File 1 - UI

@objc public protocol TestDelegateViewDelegate: class {
**func primaryAction()**
}

class TestDelegateView: UIView {
@IBOutlet private weak var button: UIButton!
weak var delegate: TestDelegateViewDelegate?
   

@IBAction private func primaryActionPressed(_ sender: UIButton) {
 print("print if before delegate executes")
**delegate?.primaryAction()**
print("print if after delegate executes")
  }
}

File 2 - ViewController

extension TestDelegateViewController : TestDelegateViewDelegate {
**func primaryAction() {**
    self.dismiss(animated: true, completion: nil)
    print("print if delegate executes")
}

When I try this code, my code does print all my print statements, yet - I get this error:

     Terminating app due to uncaught exception 'NSInvalidArgumentException', 
reason: '-[Project.TestDelegateView buttonAction]: 
unrecognized selector sent to instance 0x11bc0d2a0'

1 - Am I using delegates wrong? I need to keep the IBOutlets and IBActions in the view.

2 - Am I using MVVM wrong perhaps?

3 - What would be the best practices approach to this design pattern?

4 - why would I be getting this error here? it happens after all code runs.

Thanks so much for the help.

Upvotes: 0

Views: 436

Answers (2)

valeriana
valeriana

Reputation: 159

I found a way around this- How to implement the MVVM design pattern in full. With actions from a UIView . Yet keeping actions mostly in the View controller, with the use of a delegate protocol.

Protocol

@objc public protocol TestDelegateViewDelegate: class {
**func primaryAction()**
}

UIView file

class TestDelegateView: UIView {

@IBOutlet private weak var button: UIButton!
weak var delegate: TestDelegateViewDelegate?


@IBAction private func primaryActionPressed(_ sender: UIButton) {
 print("print if before delegate executes")
**delegate?.primaryAction()**
 print("print if after delegate executes")
  }

  init(delegate: TestDelegateViewDelegate) {
     self.delegate = delegate
   }

 }

View Controller

  class TestDelegateViewController: UIViewController {
    var view: TestDelegateView?
    viewDidLoad() {
      view = TestDelegateView(delegate: self)
       }
    }

  extension TestDelegateViewController : TestDelegateViewDelegate {
  **func primaryAction() {**
  self.dismiss(animated: true, completion: nil)
  print("print if delegate executes")
  }

Upvotes: 0

Phillip Mills
Phillip Mills

Reputation: 31016

Something -- presumably a button in your storyboard -- is wired up to a function called buttonAction. In your code, the IBAction is called primaryActionPressed.

The usual way this happens is by renaming code functions while not resetting their storyboard connections to match.

Upvotes: 2

Related Questions