可测试,嗯?是怎样?好吧,View Controller 是出了名的难以测试,因为它们做了太多事情。在 MVVM 里,我们试着尽可能多的将代码移入 View Model 里。测试 View Controller 就变得容易多了,因为它们不再做一大堆事情,并且 View Model 也非常易于测试。让我们来看看:
123456789101112131415161718192021222324
SpecBegin(Person)NSString*salutation=@"Dr.";NSString*firstName=@"first";NSString*lastName=@"last";NSDate*birthdate=[NSDatedateWithTimeIntervalSince1970:0];it(@"should use the salutation available. ",^{Person*person=[[Personalloc]initWithSalutation:salutationfirstName:firstNamelastName:lastNamebirthdate:birthdate];PersonViewModel*viewModel=[[PersonViewModelalloc]initWithPerson:person];expect(viewModel.nameText).to.equal(@"Dr. first last");});it(@"should not use an unavailable salutation. ",^{Person*person=[[Personalloc]initWithSalutation:nilfirstName:firstNamelastName:lastNamebirthdate:birthdate];PersonViewModel*viewModel=[[PersonViewModelalloc]initWithPerson:person];expect(viewModel.nameText).to.equal(@"first last");});it(@"should use the correct date format. ",^{Person*person=[[Personalloc]initWithSalutation:nilfirstName:firstNamelastName:lastNamebirthdate:birthdate];PersonViewModel*viewModel=[[PersonViewModelalloc]initWithPerson:person];expect(viewModel.birthdateText).to.equal(@"Thursday January 1, 1970");});SpecEnd
注意到在这个简单的例子中, Model 是不可变的,所以我们可以只在初始化的时候指定我们 View Model 的属性。对于可变 Model,我们还需要使用一些绑定机制,这样 View Model 就能在背后的 Model 改变时更新自身的属性。此外,一旦 View Model 上的 Model 发生改变,那 View 的属性也需要更新。Model 的改变应该级联向下通过 View Model 进入 View。
在 OS X 上,我们可以使用 Cocoa 绑定,但在 iOS 上我们并没有这样好的配置可用。我们想到了 KVO(Key-Value Observation),而且它确实做了很伟大的工作。然而,对于一个简单的绑定都需要很大的样板代码,更不用说有许多属性需要绑定了。作为替代,我个人喜欢使用 ReactiveCocoa,但 MVVM 并未强制我们使用 ReactiveCocoa。MVVM 是一个伟大的典范,它自身独立,只是在有一个良好的绑定框架时做得更好。