带有RxSwift的MVVM
背景
在开发iOS应用程序时,您知道用于开发iOS应用程序的体系结构是MVC(模型-视图-控制器),每个应用程序组件按其职责分开。
在MVC架构上,模型负责提供数据或控制与数据访问有关的所有事物。 Person
或PersonDataAccess
类是模型的示例。 View负责将数据显示到用户界面。 并且,最后一个是Controller,负责更改模型并准备要呈现给View的数据。
根据Apple MVC的概念,视图将用户操作发送到控制器,然后控制器使用从视图发送的数据更新模型,然后模型将模型中的数据更改通知控制器,最后一个是控制器更新视图。
看起来很简单,对吧? 但是现实与上面的概念并不相同。 大多数iOS开发人员(包括me😂)倾向于制作Massive View Controller。
为什么将其视为问题?
因为视图和控制器紧密耦合,很难说它们是分开的。 在这种情况下, UIViewController
子类被视为View。 因此,您倾向于将所有这些职责(网络调用,事件处理,数据更改,显示数据等)写入视图控制器( UIViewController
子类)。
似乎易于实现,但有很多后果。
- 由于表示和数据操作合为一层,因此很难测试业务逻辑(视图)
- 难以维护
- 膨胀的
UIViewController
- 继续…
由于以上所有这些问题,我开始学习一种替代的体系结构,该体系结构解决了这些问题。
认识MVVM
因此,这是视图控制器庞大性的拯救。 有一个名为ViewModel的组件。 那么,ViewModel的职责是什么?
就像MVC架构上的Controller一样,ViewModel负责更改模型并准备要呈现给视图的数据。 但是,有许多差异。 ViewModel提供了到View的数据绑定机制,因此,如果ViewModel上有数据更改,则View将自动更新,并且ViewModel没有对View的引用。
就个人而言,由于数据绑定机制,我喜欢这种体系结构,因此如果ViewModel发生更改,则View可以更新自身,并且由于职责分离,因此易于测试模型和业务逻辑。
因此,将MVVM应用于iOS开发的好处是
- 易于测试业务逻辑和模型
- 视图几乎是被动的,因为存在数据绑定,尽管如此,我们仍然使用视图控制器执行segue(作业,请分开此😂)
- 轻松更改UI而不弄乱业务逻辑
- 您可以将业务逻辑或网络调用放入ViewModel,这样视图控制器就变得不那么肿了
ViewModel的经验法则
- 无参考资料
- 没有
import UIKit
- 没有引用任何UIKit的组件,例如
UIView
,UIButton
,UITextField
等 - 只是一个数据。 JSON,字典或其他数据结构
RxSwift
ReactiveX提供的一种反应式编程框架。 这是Rx的Swift版本。 它依赖于可观察的模式,如果Observable发生了数据更改或事件,则观察者可以执行某些操作。 在这里可以找到RxSwift的更多详细信息。
在这里,我在MVVM体系结构上使用RxSwift提供从ViewModel到View的数据绑定,并在Model发生更改时通知ViewModel。
谈话很便宜,请告诉我代码!
您可以在此处访问我的github存储库,以更好地了解MVVM + RxSwift的实现。 我将解释该项目的重要课程
模型
说明:
- 上线nr。 7,我声明了一个名为
todosFromCoreData
的变量,ViewModel可以观察到。 并在线上nr。 在图8中,managedObjectContext
变量是一个用于存储NSManagedObject
对象(作为CoreData框架的一部分)的对象。 - 当有从该类实例化的对象时,初始化程序用于从核心数据中获取数据
- 数据操作,例如获取待办事项,添加待办事项,删除待办事项或更改待办事项。 更改数据后,我们必须从持久性存储中重新获取更新的数据。
视图模型
因此,在ViewModel中,我有3个成员:
-
todos
:用于将源绑定到视图 -
todoDataAccessProvider
:用于更改模型中的数据 -
disposeBag
:disposeBag
一部分,用于内存管理。 在这里可以获得更多信息
方法fetchTodosAndUpdateObservableTodos()
用于从TodoDataAccessProvider
类中订阅可观察的TodoDataAccessProvider
,如果有更新,则todos
将进行相应的更新。
第30–42行用于处理视图中的事件,例如添加待办事项,删除待办事项和切换待办事项。 我只是从todoDataAccessProvider
调用方法来更改模型。
视图
在第nr行。 9,我有一个从TodoListViewModel
实例化的成员,然后看一下viewDidLoad()
方法。
上线nr。 18,调用populateTodoList()
方法,该方法执行从ViewModel到View的绑定,然后将其呈现到UITableView
。
然后在行nr。 19,有一个调用setupTodoListWhenTableViewCellTapped()
的调用,当通过反应性包装器将项目选择为表视图委托时,该调用将执行操作。 从todoListViewModel
调用toggleTodoIsCompleted(withIndex:)
。
然后在行nr。 20,有一个对setupTodoListWhenTableViewCellDeleted()
的调用,当通过反应性包装将项目删除到表视图委托时,该调用将执行操作。 从todoListViewModel
调用removeTodo(withIndex:)
。
最后一个@IBOutlet buttonAddTodoTapped(_:)
用于处理添加Todo的事件,并从todoListViewModel
调用addTodo(withTodo:)
。
可测试性和结论
现在,View层不再那么肿胀,因为它具有对ViewModel的绑定机制,并且View只能观察ViewModel的更改。 现在,可以轻松测试ViewModel或Model😉
下一步是什么
希望您能在下一个项目中了解如何实现MVVM架构,如果有一些无法理解的内容,请在评论中告诉我。 干杯。