DEV Community

Ting
Ting

Posted on

SwiftUI与View Model:Apple的词语选择困难

前言

经过一段时间SwiftUI开发的朋友应该都注意到,Apple在其官方文档网站 https://developer.apple.com/documentation/ 上刻意地避免使用“View Model”一词。

初学SwiftUI的开发者肯定会有疑问:为什么Apple不用众所周知的view model这个单词来描述处理数据逻辑的对象,而非得舍近求远地用各种近义词替换,什么Store啦、data model啦、或者指代事物的实体名词,来命名数据对象。这篇文章简单记录一下我的发现和猜测。

简史

经历过UIKit到SwiftUI转变的朋友们应该还记得,当SwiftUI随着iOS 13在2019年推出时,最开始其实是很粗糙、很不稳定的。在数据对象这一点上,SwiftUI第一版甚至没有@StateObject这个property wrapper。

最开始时大家对新技术也是一头雾水,很多手快的教程作者写的解读文章漏洞百出,我记忆中见过的误用包括……

  • 直接在view中用let声明数据对象的
  • @ObservedObject private var声明数据对象的
  • 用单例或者变种单例的Model.shared来保证数据对象唯一性的
  • @State这个在官方示例中只用来存储"plain old data"数值类型的property wrapper来声明class对象

过了大半年,大伙逐渐玩熟了SwiftUI以后,才明白过来,并不是我们写的代码有问题,而是SwiftUI 1.0根本就没办法“优雅”地声明一个唯一的observable object。记得无论是developer forum还是swift.org的forum,都有好几个帖子讨论这个问题。最终这个问题随着Apple在iOS 14引入@StateObject而得到彻底解决。

变迁

在iOS 13到15之间,Apple自己对于数据对象的理解也在不断演化。有个新来的只接触过现代SwiftUI的小同事问我,“为啥苹果文档里,有的地方管它叫XXStore,有的叫XXModel?”我自己的观察如下:

  • “Store”: 示例文档 这个文档是iOS 14时代推出的。当时刚有的@StateObject,Apple自己还在纠结这些概念性的名词应该怎么称呼,所以并没有选择如今更为常见的“Model”来命名变量。
  • “Model”: 示例文档 当进入iOS 15的时代,SwiftUI也开发到第三版,其整体架构和稳定性都上了一个台阶。这时候Apple的命名策略也稳定下来,大致为:若一个数据对象是真实世界中实际存在的物体,如一本书Book,或者参会者Attendee,则用实际名词命名;如果数据对象是抽象的,只为了处理一个view的所有数据逻辑,则将其命名为data model。这样就可以无所顾忌地把所有“有的没的”参数全都塞到一个对象里面 🤪
  • “view model”: 示例文档 在几乎所有的Apple官方文档中,它们尽可能地避免使用view model这个词。百密一疏,还真让我撞见一个审稿疏忽的文档!可以看到,SwiftUI首页链接的数据模型概念文档里面“model”一词用了四十余次,“data model”十余次,可一次“view model”都没用。所以,我觉得Apple是故意避免使用view model这个词的。至于为什么,接着往下看……

我估摸着苹果内部开发是不在乎对象是否为ViewModel()创建。只是在对外的文档中统一口径,不用这个词罢了。你装你🐴呢

为何避免View Model?

对于这个问题最有代表性的讨论,是Apple Developer Forum上广为讨论的一个帖子:https://forums.developer.apple.com/forums/thread/699003

简单来说,很多人在写了很多SwiftUI代码后,发现刻意加入一个传统的MVVM模式中的view model是完全没必要的。传统的MVVM里view model主要用来处理数据和视图的双向绑定:数据进来,更新视图;视图状态变化,反馈给数据。直到2021年,我看到还有许多企业做demo时,宣传要合理地建模view model 说的就是你MongoDB。但实际上,除了直接在客户端操作数据库的情况以外,如今很少有需要在用户逻辑层面大量操作数据的app了。

自从Apple引入@StateObject之后,SwiftUI的数据模型虽然性能一般,但变得容易理解。数据类型用state和binding和environment,引用类型用state object和observed object和environment object。很多情况下,通过合理的access level控制和正确的property wrapper使用,双向数据绑定只需要view和model两个层面即可。以往MVC中一团浆糊的controller,和MVVM中的view model,都被简化了。

我猜Apple的本意就在这儿:能简化的问题,没必要“为了设计模式而设计模式”。诚然,我们可以根据传统的MVVM模式,为每一个视图配一个view model和一个model,但那样就增加了许多不必要的胶水代码,需要测试的代码也成倍增加。Apple就想了,干脆我们不把数据模型叫view model,刻意地让读者明白新的MV模式不涉及到手动双向绑定,这样就能扭转大家的过时的思路。

Observable更进一步

在iOS 17里,Apple采纳了社区提出的Observation模式,把原先state object和observable object的模式进一步简化。我想它的本意是让开发者把数据模型更加细化,明确哪些属性会导致视图更新,哪些不会。而不要再犯“一万行controller”的错误。

SwiftUI走过五年时光,由于兼容性的考虑,很多走错的路,只好木已成舟、顺水推舟。如果重新再来、从头设计,或许很多关键概念的选词,会有更好、更直观的选择。

Top comments (0)