【问题标题】:MVVM pattern in iOSiOS 中的 MVVM 模式
【发布时间】:2018-06-30 14:14:50
【问题描述】:

跟随 MVVM 时,ViewModel 如何获取对 View 的引用?

例如,一个UITableViewController的VM符合协议UITableViewDelegate,在-didSelectRowAtIndexPath方法中,VM如何调用navigationController.pushViewController等方法?

一个简单的解决方案是在初始化 ViewModel 时传入视图控制器。有没有其他更好的方法来做到这一点?

例如在 viewmodel.swift 中:

func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
   let vc = UIStoryboard.Main.instantiateViewController(withIdentifier: "postDetailsVC") as! PQPostDetailsViewController
   let cell = collectionView.cellForItem(at: indexPath) as! PQProductCollectionViewCell
   vc.featureImage = cell.productImageView.image

   // Cannot call the following since ViewModel is not a UIViewController
   self.navigationController?.pushViewController(vc, animated: true)
}

【问题讨论】:

  • 我以为 UITableViewController 本身已经符合 UITableViewDelegate 了?
  • 上面的代码应该是控制器的一部分,而不是视图模型。视图模型应该是惰性的并且是视图子类的一部分。它可以将任何模型对象转换为视图可以理解的格式。
  • @ArunGJ 如果代码进入控制器,它如何根据从网络层检索到的数据自定义单元格,我假设在 ViewModel 中?
  • 我相信视图模型应该只负责将数据暴露给视图控制器。您应该将视图模型放在视图控制器/视图中,而不是相反。
  • ViewModel 和 View 正在解耦。这意味着 ViewModel 不知道 View 是什么。它们通过数据绑定进行通信。如果您尝试将视图代码放在 ViewModel 中,那么您做错了并且违反了 MVVM 模式。我建议使用这个库:github.com/duyduong/DDMvvm,它有很多基类供您开始使用 MVVM

标签: ios swift mvvm


【解决方案1】:

ViewModel 是纯 NSObjectView 表示为 UIViewUIViewController 对象。您的 uicollectionView 应该在 ViewModel 附加的 UIViewController 中。 ViewModel 隐藏所有异步网络代码、模型更改等。

class YourViewController: UIViewController {

    var viewModel: ViewModel!
 .......

   func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
      let vc = UIStoryboard.Main.instantiateViewController(withIdentifier: "postDetailsVC") as! PQPostDetailsViewController

      vc.featureImage = viewModel.productImageView[indexPath.row]

      // Cannot call the following since ViewModel is not a UIViewController
      self.navigationController?.pushViewController(vc, animated: true)
   }
}

【讨论】:

    【解决方案2】:

    我遵循的一般经验法则是,如果我必须将 UIKit 导入视图模型,我做错了。 (我说一般是因为在视图模型中需要来自 UIKit 的某些东西可能是合法的用例。)

    正如一些 cmets 中提到的,视图模型旨在将某些项目公开给您的视图控制器。你应该避免直接在视图模型中做 UI 相关的事情。这会影响视图模型的可重用性,并且不允许它们独立于您的 UI 代码进行测试。

    在您的情况下,您似乎正在使用您的视图模型作为表视图委托。如果您创建视图控制器的扩展并在那里实现委托协议,从 mvvm 的角度来看可能会更好。您可以在视图控制器类声明下方执行此操作,如下所示:

    class ViewController {
    ...
    }
    
    extension ViewController: UITableViewDelegate {
    ...
    }
    

    如果您需要在委托函数中操作视图状态,您可以在视图模型中公开一个变量或函数,并从委托函数中调用它。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-06-14
      • 2016-06-29
      • 1970-01-01
      • 2012-06-18
      • 1970-01-01
      • 2016-07-12
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多