当前位置: 首页 > 面试题库 >

iOS:如何使用MVVM在视图模型之间传递模型?

魏浩广
2023-03-14
问题内容

假设我有一个模型Car,该模型在 ViewModel1中 实例化为以下初始属性:

ViewModel1

let car = Car(make: "McLaren", model: "P1", year: 2015)

然后,我需要在下一个视图控制器中完成汽车的其他信息。遵循MVVM时,在视图控制器之间传递模型的 正确 方法是什么?

使用MVC,操作很简单,因为视图可以引用模型:

vc2.car = car

以下是对该问题的伪尝试,但是我给人的印象是视图模型应该是私有的,并且只能由单个视图控制器访问。因此,以下尝试对我来说似乎是不正确的。

ViewController1

fileprivate let viewModel = ViewModel1()

func someMethod() ->  { 
    let car = self.viewModel.car 
    let vc2 = ViewController2()
    vc2.viewModel.car = car
    present(vc2, animated: true, completion: nil)
}

ViewController2

let viewModel = ViewModel2()

func anotherMethod() {
    print(self.viewModel.car.make)  //prints "McLaren"

    viewModel.manipulateCar()       //adds additional information to the car object

    print(self.viewModel.car.color) //prints "Black"

    //Pass the finished car to the last view controller to display a summary
    let vc3 = ViewController3()
    vc3.viewModel.car = self.viewModel.car
}

我想知道上面显示的是使用MVVM时的一种很好的处理方法,或者如果不是,在视图控制器之间传递汽车的 最佳 方法是什么?

编辑

这个问题与Class vs Struct无关。上面的MVC示例暗示它将成为一个类(因为它是引用),并且在多个视图控制器之间传递它以完成对象的更多部分。

这是一个问题,即在遵循MVVM时如何在视图控制器之间传递模型,以及视图模型是否应为视图控制器专用。

使用MVVM,视图控制器不应引用模型,因此不应具有变量var car: Car?。因此,您不应看到:

let vc2 = ViewController2()
vc2.car = car

看到这是不正确的吗?

let vc2 = ViewController2()
vc2.viewModel.car = car

问题答案:

这个问题与RxSwift或MVVM vs MVC无关。这是一个Class vs
Struct问题。(请注意,当模型是结构时,您的注释“使用MVC,因为视图可以引用模型,因此很容易做到”是不正确的,因为您不能将引用传递给结构。)

您如何解决此问题完全取决于您如何从视图控制器过渡到视图控制器。

当视图控制器负责过渡时。

当视图控制器负责过渡时,每个视图控制器将负责制作下一个视图控制器,而每个视图模型将负责制作下一个视图模型。通过使“父”视图模型侦听“子”视图模型(通过委托,回调闭包或可观察的响应)来完成传递回模型。

通过直接创建并呈现下一个视图控制器,或者到达其容器视图控制器(例如导航VC)并告诉其进行转换,视图控制器可以通过segue或“老式方式”进行转换。

由协调员负责过渡。

过渡的新趋势是让协调器类代替视图控制器来处理它。使用此想法,协调器保存模型,并根据需要创建视图控制器。然后,视图模型与协调器对话,而不是(可能创建并)彼此对话。这样,视图控制器便彼此独立。

您可以使视图模型使用委托,闭包回调或Rx Observables与协调器进行对话。

根据您的修改进行更新:

您问拥有它是否不正确let vc2 = ViewController2(); vc2.viewModel.car = car。答案是肯定的,那是不正确的,但是很接近。

如果视图控制器负责过渡,那么您将看到的是:

// in view controller 1
let vc2 = ViewController2()
vc2.viewModel = self.viewModel.viewModel2

如果使用协调器,则会看到类似以下内容的信息:

// in coordinator
let vm2 = ViewModel(car: self.car)
let vc2 = ViewController2(viewModel: vm2)

视图模型背后的关键思想不是私有的,不必一定是私有的。关键思想是它是视图控制器持有的唯一非视图对象。您可以将其视为“模型控制器”。



 类似资料:
  • 我正在尝试取消api请求,如果用户调用api来加快速度,那么只有最新的api才会返回结果,所有以前的请求都应该被丢弃,但这不起作用,任何人都知道解决方案,请帮助,谢谢 类CartViewModel(val store:Account):base viewmodel(){ 私有var请求计算:作业?=空 fun重新计算(){ }

  • 问题内容: 我的结构是这样的: 而结构是: 我主要尝试这样做: 是否可以在模板内部执行类似的操作? 问题答案: 引用的文档,该操作的语法: 这意味着您可以将一个可选数据传递给模板执行,而不是更多。如果要传递多个值,则必须将它们包装为传递的某个单个值。 因此,我们应该将这些数据包装到struct或map中。但是我们不能在模板中编写Go代码。我们可能要做的是注册一个函数,将这些数据传递给该函数,该函数

  • 我对如何在两个模型之间传递数据有疑问。 所以我想把状态从单元传递到主模型,并在那里进行反应。例如发送请求。

  • 我已经将一个Yolo模型转换为.tflite,以便在Android中使用。在python中就是这样使用的-- 我使用netron https://github.com/lutzroeder/netron可视化模型。输入描述为name:inputs,类型:float32[1,416,416,3],quantization:0≤q≤255,位置:399,输出描述为name:output_boxs,类型

  • 问题内容: 我想知道在视图之间传递数据的“最佳”方法是什么。创建不可见字段并使用POST传递它是否更好,还是应该在URL中对其进行编码?还是有更好/更简便的方法? 问题答案: 在视图之间传递数据有多种方法。实际上,这与在两个不同的脚本之间传递数据的问题并没有什么大的不同,当然还引入了一些进程间通信的概念。我想到的一些事情是- GET请求 -第一个请求命中view1->将数据发送到浏览器->浏览器重

  • 背景: 我有一个支持bean,它有上传方法,可以在上传文件时监听。现在我将这个文件传递给解析器,并且在解析器中对csv文件中存在的行进行验证检查。 若验证失败,我必须记录信息并保存在数据库的日志表中。 我的最终目标: 就是在日志bean中获取会话信息,这样我就可以获取并调用将数据保存到数据库中。 正在发生什么: 在我的上传支持bean中,我正在获取会话,但当我调用解析器时,我不会传递会话信息,因为