MVVM的典型开源项目下载地址:https://github.com/kopuCoder/SXNews。 MVVM( Model-View-ViewModel子控件的事件驱动模型),也就是轻量级的控制器架构。它本质上就是MVC的改进版。MVVM 就是将其中的View 的状态和行为抽象化,让我们将视图 UI 和业务逻辑分开。Model就是Entity,定义数据;View实现视图 UI;ViewModel负责请求发送及业务逻辑;UIViewController只负责生成数据(Model),View(视图 UI),ViewModel(请求发送及业务逻辑)三者的对象与协调他们完成具体的页面。
软件开发人员的两种典型错误思维
1.头脑风暴。
2.盲目反对。
纯粹的头脑风暴会让你只看到软件方案和架构的优点,避而不谈它的缺点。软件不可能永远存在云上,它会落地的,当它落地时,会出现这样和那样的问题。
盲目的反对更要不得,这也不行,那也不行,只看一种方案和架构的缺点,看不到优点,那不是什么都不要做了。每个人由于习惯使然会偏向这两种做法,需要从心理上克服这种偏颇,采用包容的心态。
苹果客户端开发的三种境界
1.无明显架构的无序开发(新人的初始状态),想的是MVC架构开发,由于技术知识不足或懒惰,只追求速度,把一个页面所有的逻辑和控件都在该页面的控制器里完成,不去抽象控件,不去抽象模块。一个xib和控制器包打一个页面的天下。这样的架构和思维要不得,可以当自己学习新技术使用,不要用到具体的软件开发中去。
2.MVC(Model View Controller)架构开发,它是苹果推荐的开发模式,它把页面分成三部分:数据模型,页面视图,页面控制器。一个页面被分成多个小视图,一个页面共享一个数据模型,只是这个数据模型只被控制器操作,不被各个子视图处理。这个架构看起来整洁多了,控制器的复杂度降低的很多,页面的显示单元被分配到各个视图去显示,控制器专注与数据的加工与处理,部分解放了控制器,使它的功能更集中,更紧凑,更小。数据模型,页面视图,页面控制器各个独立,各司其职。这就是重量级视图控制的特点。它看起来简单,更容易理解,所有的逻辑在视图控制器里处理。一个页面一般分三个文件夹:页面文件夹(存放页面控制器和其子文件夹),页面文件夹下的model文件夹,页面文件夹下的view文件夹。想找页面间的逻辑就去页面控制器里找,想看页面显示元素就在view文件夹下寻找。你发现数据文件很小,只是数据存储和转换,这符合数据单一性原则;视图部分也很小,只是数据的显示,完全不自主;控制器部分仍然摆脱不了过于庞大的弊病。他们就像一个人一样头重而且庞大,脚轻,身子小。看到这些你就知道这种开发架构需要进化的方向:强化控制器的重要性,减轻它的体积,把不属于它的非核心部分迁移到类似视图的那一部分去,在保证数据的定义性上增加它的功能和作用。取消使用单例组装http请求的做法(单例像类一样常驻内存,无形中增加类内存的开销。虽然它做到了统一管理http请求的作用,但是不符合那个页面的请求那个页面管理请求的原则)。让从控制器分化出来的这一部分功能给View,http请求封装为一个新操作类。
3.MVVM( Model View-Model Controller View)就是MVC设计模式的更先进进化,符合它进化的方向。每个人对MVVM了解不同和使用技术不同,最终实现的MVVM架构也不同。
数据源被强化,不单只是请求过来的数据还包括,数据在本页面应该处于的状态(例如:根据请求,支付页面是企业支付,不需要显示第三方支付选择框,model增加了这样的状态。当然这样的状态可以改变,用户重新选择了支付方式,选择个人支付,该状态要根据用户的行为而改变。),数据源对象在本页面或本模块中共享,一旦一个地方改变,本页面或模块中的所有数据源的内容都改变,保证了数据的一致性。它的全局共享性是它的一大特色。
从控制器分离出来的非页面间关系部分和http请求部分,产生请求操作类.它可以被控制器调用,也可以被view调用。它负责数据数据请求参数的组装,甚至上次请求的暂存,服务器请求过来的数据转化为数据源数据,进行简单数据处理。我们称它为View-Model。一个页面可以有一个View-Model,也可以有多个View-Model,这个可以根据页面的复杂度和View(调用View-Model的View)是否在其它页面重用。若有View调用请求对象发送请求并且被其它页面重用该View,那么该View不能共享数据源。View-Model一般持有本页面或本模块的共享数据源。
控制器专注于自己的核心功能:页面的跳转,跨本页面多个视图的操作,数据源数据的初始化,从上一个页面接收数据转化为本页面的数据源(有的页面不发送请求只是显示数据,有的页面需要上也个页面接收关键字段(如“订单号)作为本页面请求的参数),子视图页面的创建和布局,子视图页面的block函数,状态栏,导航栏,页面跳转方式(有的页面需要跳转后销毁本页面—地图页面);有的页面出现后需要常驻内存,不能销毁本页面–Tabbar页面),在dealloc中销毁移除通知。除了这些核心事件外,其它的都可以移置到View或View-Model中处理。控制器持有本页面或本模块的共享数据源。
控制器相对的并不是只有父类为UIViewController的类才是控制器。当也个页面过于复杂,被分成了多个层次时,可以通过在[[[UIApplication sharedApplication] delegate] window]增加view。这个新增加的View本身就和控制器的功能一样。这个可以做到一层页面就是一个控制器。
当然也可以下面的方法创建window。这个window也是和控制器一致。 self.currentWindow = [[UIWindow alloc] initWithFrame:CGRectMake(0, 0, FULL_WIDTH, FULL_HEIGHT)];
self.currentWindow.windowLevel = UIWindowLevelStatusBar;
self.currentWindow.opaque = NO;
[self.currentWindow makeKeyAndVisible];若用创建window的方法创建视图控制器时需要在销毁这个window时调用[[[[UIApplication sharedApplication] delegate] window] makeKeyAndVisible];来使原来的window显示。由于该方法实际上向主线程发送的一个通知,等刷新UI线程调用了响应的处理才执行,就是它是异步执行的,所以当页面首次加载时有可能页面显示不出来的情况。所以这种方法建议慎用,采用上一种方法更安全。
View增强了两大功能:持有全局数据源,根据数据源进行显示和布局;可以直接调用请求对象发送请求,来刷新数据或页面跳转。可以看到View已经具有部分控制器的功能(调用View-Model发送http请求,刷新页面),并且View根据抽象的需要可以在不同页面或模块间共享使用。
MVVM一般包含页面(或模块)总文件夹,Entity文件夹(model对象或模块内的编译宏),View文件夹(视图文件,该文件夹下可能包含子ViewModel文件夹),图片库(Assets.xcassets),ViewController文件夹(控制器对象),ViewModel文件夹(http请求对象)。除了这个5个基本文件夹外还可能包含序列化model的文件夹。
MVVM设计模式的优点
1.双向绑定技术,当Model变化时,View-Model会自动更新,View也会自动变化。很好做到数据的一致性,不用担心,在模块的这一块数据是这个值,在另一块就是另一个值了。所以 MVVM模式有些时候又被称作:model-view-binder模式。
2.View的功能进一步的强化,具有控制的部分功能,若想无限增强它的功能,甚至控制器的全部功几乎都可以迁移到各个View上(不过这样不可取,那样View干了不属于它职责范围的事情)。View可以像控制器一样具有自己的View-Model.
3.由于控制器的功能大都移动到View上处理,大大的对控制器进行了瘦身。不用再为看到庞大的控制器逻辑而发愁了。
4.可以对View或ViewController的数据处理部分抽象出来一个函数处理model。这样它们专职页面布局和页面跳转,它们必然更一步的简化。
【长篇高能】ReactiveCocoa 和 MVVM 入门(http://www.cocoachina.com/ios/20150526/11930.html)就是MVVM设计模式头脑风暴提唱者。其实它没有那么神,它也有很多固有的缺点,而且有的优点其实也是缺点,并且不容易改进。 MVVM设计模式的缺点
第一点:数据绑定使得 Bug 很难被调试。你看到界面异常了,有可能是你 View 的代码有 Bug,也可能是 Model 的代码有问题。数据绑定使得一个位置的 Bug 被快速传递到别的位置,要定位原始出问题的地方就变得不那么容易了。
第二点:一个大的模块中,model也会很大,虽然使用方便了也很容易保证了数据的一致性,当长期持有,不释放内存,就造成了花费更多的内存。
第三点:数据双向绑定不利于代码重用。客户端开发最常用的重用是View,但是数据双向绑定技术,让你在一个View都绑定了一个model,不同模块的model都不同。那就不能简单重用View了。
被误解的MVC和被神化的MVVM这篇文章是MVVM彻头彻尾的反对者,好像该设计模式一文不值。我只能说他太偏激了,只顾着指责,没有看到他最显然的优点和改进。 MVVM设计模式的优缺点之我见及改进
MVVM更高级更先进表现在解放了控制器(Controller),就是轻量级控制器。这个批评者也没有否定。MVVM不影响代码重用,其实抽象出来的一个一个小View就是为了代码重用的。反对者所谓的把网络请求封装到类里也就是View-Model。
其实对它贬低最多的只剩下集优缺点于一身的双向绑定技术。那么他们也不治之症,也可以改进。
对于调试困难的问题,确实存在,可以通过日志系统来定位,对数据被修改的地方进行敏感的地方进行日志打印。不会你的软件没有日志系统吧?
对于影响内存问题,你可以通过划分模块时,把一个页面或两到三个页面划分为一个模块,那样应用的model也不大,内存开销很小。我大都把每个页面多划分一个模块,减少耦合度,软件开发的高内聚低耦合的设计思想大家都懂吧!若把一个项目的数据都整合到一个面面俱到的model, 那除非傻子才那么做,就是那样做了,那也不符合MVVM模式了。
对于数据双向绑定不利于代码重用确实是一个问题。基本上重用的代码model都不相同。你可以对这两个model抽象成一个组合model.也可以观察你这个View需要哪些必须的数据,把它当变成成员变量,让他不绑定model.若这个View在两个模块使用,并且发送请求,那么你可以给这个View抽象为一个新的View-Model.
若真像《被神化的MVVM》那篇文章说的那样改进MVC设计模式,那么它就不是 MVC了,它更像不采用ReactiveCocoa的 MVVM了。
【长篇高能】ReactiveCocoa 和 MVVM 入门这篇文章给我们影响最深刻的是ReactiveCocoa的一切皆信号。其实也就是封装了一层block,没有什么神秘的,不过使用起来确实方便,值得推荐,若你会使用原来的老方式也没有什么掉价,并不是你不是你不使用ReactiveCocoa就不是 MVVM.它说了半天完了半天文字动画也没有说明 MVVM的本质,它的本质其实就抽像出来http请求类,增强View的功能,让它像控制器一样发送请求和刷新UI,甚至跳转页面。但是它说出了MVC向MVVM进化的根本方向:对控制器瘦身,增强View的功能,数据双向绑定。但是最关键是只说了优点,没有说它的缺点。兼听则明,偏信者暗。
我相信MVVM比MVC设计模式更先进,值得推荐,ReactiveCocoa 有助于MVVM的使用,它的另一个优点,更有助于模块化。并非文章说为了实现一切皆信号的境界。
既然ReactiveCocoa能有现成的实现MVVM设计模式的方案,而且便于实现软件模块化。那么没有必要必要盲目的反对,可以欣然接受,但是还没有达到盲目非使用不的地步。使用该设计方案,就要用到pods,不然很麻烦,我没有试过替代方案。
我们应该跳出方法论的怪圈,致力那种方案能使我们的软件更容易理解,更容易模块化就用那种方案。使用ReactiveCocoa会引入它的框架,需要使用pods。你不会可能感觉到心理上抗拒采用该技术,一旦你引入了该框架,学会了该技术,它会一劳永远给你以后的开发带来很多方便。