具有Cocoa键值观察器的简单iOS MVVM

为什么使用MVVM

与使用MVC相比,使用MVVM体系结构构建iOS应用程序具有许多优势。 优势之一是通过将模型和视图分离到单独的MVVM对象来减少Massive View Controller问题,View Controller的职责是仅在ViewModel中 观察与视图相关的值,然后在值更改时更新视图。

这导致View Controller与模型之间的耦合较少单元测试变得更加容易,因为我们可以将ViewModel与View Controller分开进行测试

iOS应用中MVVM的当前状态

许多使用MVVM架构构建的iOS应用程序都使用第三方库(例如RxSwift和RxCocoa)来观察视图模型对视图控制器的更改。 RxSwift是一个非常强大的库,我们可以将其转换观察器与组合,合并,zip和许多其他强大的转换一起使用。

尽管RxSwift功能非常强大,但有时我们只想使用本机Cocoa Foundation框架构建没有第三方依赖性的简单小型应用程序

使用不依赖第三方的MVVM

Apple Foundation Framework提供了任何可用于在iOS体系结构中构建MVVM应用程序的内置解决方案吗? 是的,答案是Cocoa Key Value ObservingKVO观察者模式 ,可用于观察以NSObject作为其超类的对象中的属性更改的值。

可可KVO是一种非常强大的机制,可用于在iOS中构建基于MVVM的体系结构。 缺点是语法使用起来非常冗长,我们必须手动保留和删除观察者, RxSwift提供了addToDisposeBag方法,该方法可用于自动删除观察者

实施KVO以构建基于iOS MVVM的应用

这是示例iOS应用程序,当用户在TextField中键入内容时,该应用程序实现了KVO以构建简单的电子邮件验证。 该应用程序分为3个主要组成部分:

  • ViewController是一个UITableViewController ,它显示UITextField来输入电子邮件,而UILabel来显示电子邮件是否有效。
  • EmailModel是一个普通的Swift类 ,用于存储电子邮件的字符串和表示电子邮件是否有效的布尔值。
  • EmailViewModel是一个Cocoa NSObject超类,它提供了将显示电子邮件文本以及它是否为有效电子邮件格式的属性。

电子邮件模型

EmailModel存储电子邮件的值文本和表示电子邮件是否有效的isValid布尔值。 值更改时使用Swift属性观察器,使用包含有具有新值的userInfo的NotificationCenter来发布带有EmailModel.TextDidChange的Notification ,它还通过调用validateEmail来 设置isValid的值 ,并将电子邮件文本的newValue传递为使用RegEx表达式评估。 isValid布尔值中更改也通过NotificationCenter发布

EmailViewModel

EmailViewModel基于NSObject超类的MVVM该类接受EmailModel作为其构造函数。 它提供了使用objc动态关键字的 emailTextValue和isValidValue, 当使用Swift声明该类时,该 关键字可用于向属性公开KVO。

NotificationCenter用于观察EmailModel文本值和isValid值何时更改,然后使用userInfo词典中新值 更新 emailTextValue和isValid值。 任何要显示电子邮件值及其格式有效性以更新其视图的视图控制器都可以使用ViewModelEmailViewModel还公开了可以用新的电子邮件文本值调用以分配给EmailModel的 公共方法

ViewController观察者到EmailViewModel

ViewController类EmailViewModel为其属性进行依赖项注入 ,当使用情节提要时,可以在调用prepareForSegue时从先前的视图控制器 注入此属性

watchViewModel方法内部, ViewController观察EmailViewModel中的emailTextValue和isValid Keypath。 当EmailModel中的新值更新时ViewController将接收新值,然后将该值分配给TextField。 isValid更改用于确定电子邮件是否有效,然后使用UILabel显示消息。

我们没有RXCocoa来观察UITextField中的变化,因此当TextField 编辑值事件随着用户类型的变化而变化时,我们使用旧的Cocoa Target Action Selector调用该函数。 在该方法内部,我们调用EmailViewModel更新emailTextValue,并传递TextField的新值 。 这提供了View和ViewModel之间的双向绑定

结论

紧密耦合的MVC架构相比,使用MVVM架构构建iOS应用程序具有很大的可维护性和可伸缩性 。 我们可以使用简单的Cocoa KVO来绑定Model,ViewModel和ViewController,而无需使用RxSwift之类的第三方框架 。 对于一个简单的项目,它非常好,但是强大的RxSwift转换功能在我们构建具有多种状态组合的复杂应用程序提供了更大的灵活性 。 您可以在项目Github存储库中查看完整的示例代码 。 我还要提到一本最好的iOS书, objc.io App Architecture书,这为我撰写本文提供了灵感。