2017-06-23 18 views
2

因为Swift/Objective-C支持编写扩展,所以我在模型的扩展类中编写“ViewModel”属性,并在通常使用ViewModel的地方使用此扩展。为什么在iOS中使用View Model(MVVM)?

我知道分机不能有存储性能。但是大多数MVVM体系结构不推荐ViewModel中存储的属性(除了那些用于缓存的属性)。

我与维护单独的视图模型对象主要麻烦与模型得到它同步。是的,有很多第三方框架可以帮助使用反应式编程技术进行同步。但是,对于什么可以解决,通过简单地使用扩展,为什么使用一个沉重的框架实现相同?

我没有击中基于MVVM架构扩展我的一个路障。你们有没有人尝试过这种方式,并转而采用响应式编程架构?

+0

大多数情况下,我的@import UIKit几乎总是处于“ViewModel”扩展模式。 – Mugunth

+0

http://www.sprynthesis.com/2014/12/06/reactivecocoa-mvvm-introduction/ –

+0

究竟为什么要这么做?我注意到NSManagedObject的子类是以相同的方式生成的,它是空的,但扩展中的属性。 ViewModel应该是objc中的结构体或NSObject。 –

回答

2

我对扩展方法的糟糕体验是my March 2016 talk at iOSoHo in New York的第一个也是最重要的部分的基础。我所说的关于扩展的大部分内容并不在幻灯片中。扩展方法有以下几个问题:

  1. 您只能有一个模型到视图的映射(没有另一个中间层来提供逻辑协调扩展属性)。这极大地损害了视图的可重用性。
  2. 关于第1点,即使你身边这个坐标,你可能会得到碰撞,如果你使用的型号很多地方,例如name再后来加入firstNameOnly等绝对是一个模型只能不断遵循协议的一种方式,如果你想要这样做。
  3. 提供了替代模型的虚拟值,做汽车设计,调试,故障情况等,几乎是不可能的。您可能会发现自己正在为此编写一个结构 - 这是一个ViewModel。
  4. 如果您有一个视图需要多个模型来填充模型,或需要模型外部的信息,则视图模型会简化它们之间的协调。

通过ViewModel,这些重要情况变得微不足道。 (在演讲中,我所说的“命令”,因为他们完全匹配的四种设计模式定义命令刚; 设计模式笔记也被称为行动,即UIAlertAction)

我采取的做法是一个“ ViewModel“应该是轻量级的,不可变的,并且通过单向数据流分布。他们已经存储了属性,但是这只是为了移动数据,虚拟机本身是不可变的,一次性的。这与2017年3月iOSoHo上的Facebook提到的方法类似,但我认为他们不称他们为视图模型,只是轻量级对象。你可以在那里放置更复杂的逻辑,但最好是最多可以调用其他地方处理的更复杂的逻辑。

另外一个我认为是关键的问题,我的规则是,无论您称之为“ViewModel”,都不应该有程序员无法编写线框的属性。因此,一个var dateString : Stringvar date : NSDate。这是我在幻灯片中的厚脸皮术语,即“Modal Object Attribute Transformer”。但是有一点很重要:城堡需要能够吊起吊桥并在围困时进行;当网络中断(或还不存在)时,视图需要完全正常运行。如果您的观点能够做到这一点,您将在许多场景中拥有更容易的时间。

就在几个星期前,我采用了这种方法,并且能够在大约4天内创建多个复杂的屏幕,仅从设计开始工作,最终将由来自网络的数据填充,但目前没有任何模型或网络层。当数据层准备就绪后,我可以简单地编写一些创建方法init(with: Model)或更好static func withModelforCase1(_ model: Model) -> ViewModel并在创建方法中写入映射,然后在连接模型时,用这些创建方法替换static func debugCase1() -> ViewModel。随着模型的发展,编译器会在这里抛出错误,只会在这里抛出错误;随着视图的发展,调整ViewModel,再次,编译器会在这里抛出错误,而且只会在这里抛出错误。没有其他代码需要被触及。

扩展在开始时看起来非常优雅,但实际上在模型和视图之间创建了紧密耦合。某种ViewModel方法是一个强大的系统,可满足现代iOS应用程序的需求 - 以及现代iOS应用程序开发。

+0

可能是最接近其他答案的答案。 – Mugunth

+0

@Mugunth是的架构问题总是成为临界意见,但可以通过事实考虑得到通知,例如在第2点中,模型只能以一种方式符合协议(注意这一点 - 我意识到了这是困难的方式)。没有试图说服你ViewModels是“更好”,只是回答你可能使用它们而不是扩展的“为什么”。我认为很多人都有一个很好的问题。感谢接受。 –

1

ViewModel应该是从建筑POV不同的实体,而不是从代码布置POV。您对MVVM进行模型扩展的方法会使模型知道太多并且违反了SRP,例如,如果模型具有某个日期属性,则视图模型通常会用于使用当前语言环境对其进行格式设置。如果Model是数据存储,它应该只包含相关的数据结构并且不包含任何方法。如果Model是服务(例如网络客户端),它应该只包含相关的方法,只需要最少的数据转换(例如json to struct)。

而且在我的实践我有时有一个以上的虚拟机的单一模式。如果说,我有一个User模型firstNamelastNameemail属性,我可能需要fullName属性为(以UserCellViewModel实现)表行中显示出来,但在详细视图显示用户信息时,所有三个属性(UserDetailViewModel实施)。通过对模型的扩展,所有四个属性(fullName在扩展中实现)都可以在所有情况下访问。使控制器消耗ViewModel尽可能少知道是一件好事(需要引用)。这可以在Objective-C中实现,其中你的扩展可以拥有自己的头文件/接口文件,但是你在Swift中没有这样做。 MVVM 视图模型的

+0

为“隐藏”属性,我经常使用'公共私营(套)'声明。 – Mugunth

+1

'公私台(套)'只是隐藏二传手,而不是物业本身。 OOP和封装是基于需要知道的基础。因此,它是更好地隐藏它完全,而不是承诺自己不使用它时,你不需要它。) – Eimantas

2

好处是把你的验证逻辑用户输入,视图呈现逻辑,网络请求的好地方。结果,ViewController文件变得臃肿得多。 另外,View-ViewController组件与模型完全隔离。所以在开发过程中,一个开发人员可以在屏幕的UI部分工作,另一个开发人员可以独立地并发地处理屏幕的逻辑。 很容易重新设计用户界面而不会与模型逻辑混淆,因为它们都是完全隔离的。只要将适当的属性链接到ViewModel,就可以交换视图组件。这给了用户界面更多的自由体验。 对于通用应用程序,iPad和iPhone ViewController都可以与相同的ViewModel进行交互。 测试起来比较容易。开发人员可以在没有视图的情况下为ViewModel和模型创建单元测试。

+0

这正是为什么我使用模型的扩展。有没有一部分,这是不可行的使用扩展? – Mugunth

+0

你可以以任何方式做任何事情,如果你愿意,你也可以让你的整个应用适合AppDelegate,但这不是一个好习惯。良好的代码遵循SOLID原则,您的解决方案不适用,尤其是SRP –

相关问题