見出し画像

プロトコルでViewModelのイベントを検知するには?

URL: https://stackoverflow.com/questions/55902105/swift-mvvm-use-protocol-to-handle-viewmodel-events

今晩もぽっ活していきます。
今回はswiftのMVVMアーキテクチャに関するスタックオーバーフローを訳して行きたいと思います。

● 質問

delegateを使ってMVVMを実装し、ViewCotrollerのなんらかの変化をViewModelで検知したいです。
しかし, ViewModelのイベントをViewControllerで実装するとViewModelのプロトコルがセットできません。
以下がエラー文です。

Argument type (SecondViewController) -> () -> SecondViewController does not conform to expected type SecondViewModelEvents
// 引数が正しくない

実装が正しくないですか?ViewModelのコードを載せます。

protocol SecondViewModelEvents {
     func changeBackground()
}

class SecondViewModel:NSObject {
      var events:SecondViewModelEvents?
      init(del:SecondViewModelEvents) {
            self.events = del
      }
      func loadDataFromServer() {
          self.events?.changeBackground()
      }
}

ViewController;

class SecondViewController: UIViewController,SecondViewModelEvents {
       let viewModel = SecondViewModel(del: self) //Argument type         '(SecondViewController) -> () -> SecondViewController' does not conform       to expected type 'SecondViewModelEvents'

@IBAction func buttonPressed(_ sender: Any) {
      self.viewModel.loadDataFromServer()
}
func changeBackground() {
      self.view.backgroundColor = UIColor.red
}
}

● 答え

ViewModelからViewControllerに準拠する際にイニシャライズできていません。
イニシャライズについてswift公式リファレンスがとても有益なガイドを提示しているので確認してみてください。

protocolを使うためにclassを準拠する。

protocol SecondViewModelEvents: class {
    func changeBackground()
}

delegateにわかりやすい名前をつけて、強参照にならないようにweekでdelegateの変数を実装する。

class SecondViewModel {
     weak var delegate: SecondViewModelEvents?
     init(delegate: SecondViewModelEvents) {
     self.delegate = delegate
      }
      func loadDataFromServer()
      {
      delegate?.changeBackground()
       }
}

awakeFromNib()メソッドのような適切な場所でViewModelをイニシャライズします。

class SecondViewController: UIViewController, SecondViewModelEvents {
      var viewModel: SecondViewModel?
      override func awakeFromNib() {
         super.awakeFromNib()
         viewModel = SecondViewModel(delegate: self)}@IBAction func           buttonPressed(_ sender: Any) {
       viewModel?.loadDataFromServer()
  }
   func changeBackground() {
          view.backgroundColor = UIColor.red
     }
}

それかもう一つの方法としてViewModelをノンオプショナルで保持して、required initializerでイニシャライズする方法もある。

var viewModel: SecondViewModel

required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
self.viewModel = SecondViewModel(delegate: self)
}

~~~~~~~~~~~ここまでが訳です~~~~~~~~~~~~~~~~~~~~

この記事が気に入ったらサポートをしてみませんか?