在下一个项目之前,请学习MVVM

我不是iOS开发专家。 经过一个月的学习,我最近开始在Swift中为多个行业开发应用程序。 我确实喜欢每个初学者,并打开了Apple文档,并遵循了他们的指南。 苹果公司推荐的模式是MVC模式。 我按照大家都知道并珍惜的Model View Controller的经典原理开始构建自己的第一个应用程序。 从表面上看,iOS开发中的MVC模型与我们多年来使用的模型没有什么不同。 对我来说不幸的是,我一直对软件体系结构,简洁的代码和漂亮的软件感兴趣,因此将iOS和MVC结合使用非常麻烦。

几周后,随着视觉和幕后应用程序变得越来越复杂,问题就显而易见了。 在为iOS开发时,您的视图(也称为Storyboard)是一个简单的XML文件,其中包含所有不同的组件以及它们的坐标和约束。 这样做的结果是,与实例的实际功能相比,负责实例化和管理这些视图的ViewController文件变得混乱而庞大。 您开始在同一类中查看混合在一起的不同关注点:路由,模型处理,动画,视图填充…都在一起💀。 这种使用起来令人困惑和痛苦的方法,通常被称为Massive View Controller综合症。 于是去寻找其他选项,然后在此处输入MVVM

MVVM模式或模型视图ViewModel围绕应将模型处理和视图处理分开的想法而展开。 这样可以实现更好的可测试性,可读性并易于开发。 为此,我们将ViewController分为二。 View (仍然继承自Apple ViewController类)将填充视图并管理动画。 屏幕上显示的所有内容均受其控制。 ViewModel负责与API,数据库和其他信息源进行交互,并提取与其相应视图有关的信息。 实例化视图时, View将自身绑定到其ViewModel并将根据ViewModel提供的数据进行更新。 有多种方法可以实现这一点,但是Swift提供的我的首选方法是通过闭包。

为了说明这一点,让我们想象一个打印当前日期的愚蠢视图。 我们可以从设计ViewModel开始:

简单的ViewModel示例

这里, ViewModel公开了一个变量和一种方法。 fetchDate()方法将获取当前日期并为其分配一个私有变量。 每次设置此变量时,都会调用一个可选的公共方法updateDate 。 此方法是一个公共变量,可以通过View设置这样的方法:

简单检视

实例化ViewModelView会将其闭包简单地附加到其ViewModel的公开变量,然后触发获取。 如果需要,setupView方法将使用初始内容填充视图。 当获取成功完成并且在fetchDateFromApi函数上updateDateClosure了回调时,将updateDateClosure并更新标签。 所有这些异步且易于维护。

唯一令我烦恼的是, View仍然必须通过prepareForSegue和其他方法来处理路由。 在实现表示和模型处理之间的清晰分离之后,我们不能简单地乐于在这种情况下进行路由。 为了解决这个问题,我创建了一个简单的路由器协议(与旧接口的Swift等效):

基本但清晰的路由器实现

viewController的init方法是一种便捷的init方法,无需查找相应的Storyboard 。 枚举和协议只是为了清楚起见。 但这使我们可以在文件中简单引用此路由器:

将路由器添加到先前的类中

而且,我们可以使用route?.navigate(.home)轻松浏览页面。

这种模式非常简单,易于实现且易于学习。 它仍然有一些陷阱,您需要注意:

  • 模式的封闭性和异步性使其难以调试。 调用每个方法会使堆栈迅速变得混乱。
  • 注意强大的引用,以避免闭包和类变量中的内存泄漏。 例如,如果您忘记了路由器对视图的引用中的weak关键字,则它们将互相引用一个强引用,并且永远不会从内存中释放。

我不能高估一个好的架构可以带来多少变化。 有了良好的体系结构,实现功能将变得轻松快捷。 无论您喜欢哪种架构模式,在下一个项目之前,请尝试MVVM VM。 如果您对该主题感兴趣,还可以阅读有关Viper和MVVMC的信息。