在这节课你会学到MVVM设计模式的运用,让我们先简单回顾一下MVC-N,以及它的不足。
在之前的demo中我们提到了三种一般的目录:model、view、controller。其中,点击事件由controller处理,通过networking client 加载数据,同样应该由controllers处理,把模型数据转化为界面视图显示还是由controllers完成。只不过controllers不是最好的做模型数据处理的地方。
幸好另一种设计模式可以处理这些:MVVM( model view view model )隆重登场~
你可能已经猜到了MVVM拆开的话是:models, views, 和 view models.
well,view model是个什么鬼?他对我们可爱的controllers做了什么?
让我们深入了解下MVVM:Controllers在MVVM设计模式仍然存在,但他不再是主要的重点, view models才是。
controller不再直接拥有models,而是拥有 view models,而view models 会持有models。
view models作为model的一个中间人而发挥着重要的作用:处理把模型数据转化为界面视图显示
接下来,在Demo中,你会:
创建一个 product view models,重构现有的controllers,让我们开始给controllers瘦身吧!
用模拟器运行Demo,选择 Home Services—>点击第一个产品图片,然后你会看到一个关于商品的描述的界面。一般来说,这个地方需要做许多数据处理,同时,这里有一个很明显的bug:图片显示的商品不对,让我们打开Xcode查看一下发生了什么:
在导航区域选择Cleaning Services—>Controllers—>product details view controller—>view did load(),我们会在方法中看到许多数据处理的代码。但是在MVVM设计模式下,数据处理不应该在 product view controller,应该在 view model中处理
我们要新建一个组来放view models,新建一个 product view model文件放进去,我们已经说过view model会直接拥有model,所以把 product 作为 product view model的一个属性,同时在初始化中设置一下:
import UIKit
public final class ProductViewModel{
public let product: Product
public init(product: Product){
self.product = product
}
}
然后我们在assistant editor 打开product details view controller(按住Option,然后点击product details view controller)
在product details view controller你会看到outlet对每个View一对一的映射:description label, image view, price label,这样做的话在在view did load()方法设置起来会很容易
让我们继续添加text, image URL,
price text、title作为属性,同时把他们添加到初始化方法
这里有个小问题:price需要使用number formatter转换一下,所以我们需要把number formatter也作为viewmodel的一个属性
因为这个属性外部不会调用所以我们创建一个lazy static property:
internal static let numberFormatter: NumberFormatter = {
let numberFormatter = NumberFormatter()
numberFormatter.locale = Locale(identifier: "en_US")
numberFormatter.numberStyle = .currency
return numberFormatter
}()
ok,现在我们可以使用这个view model了,我们去 product sales view controller中把product model 用 product view model替换掉。
首先我们要把product属性换成product view model,然后修改 view did load()方法。
public var productViewModel: ProductViewModel!
public override func viewDidLoad() {
super.viewDidLoad()
descriptionLabel.text = productViewModel.descriptionText
imageView.rw_setImage(url: productViewModel.imageURL)
priceLabel.text = productViewModel.priceText
}
最后update ProductsViewController中 prepare(for segue:)方法
viewController.productViewModel = ProductViewModel(product: product)
重新运行,再点进product details view controller来看,一切运行完美,图片显示错误的bug也被修复了。
Product details view controller看起来瘦身了一些,但是 products view controller并没有,所以需要你在challenge去实现.
需要提醒的是有很多方法都可以实现MVVM,并且程序员们对MVVM也有各式各样的想法,例如:在Demo中,我们的controllers仍然有很多逻辑。另一些程序员更倾向于把所有的逻辑处理移到view models里,条条大路通罗马,事实上这样做也可以。
关键在于创建 view models来处理数据转换,如果你觉得把逻辑处理移到 view models很好,you can do it~只是需要注意不要把 view models弄的太大。
拜拜。