MVVM开始

参考资料

https://segmentfault.com/a/1190000003894677

https://www.raywenderlich.com/62699/reactivecocoa-tutorial-pt1

FRP(Functional Reactive Programming) 函数响应式编程

理解:
a = 5;
b = a + 5;// b = 10;
然后 a变成了6,那么如果不执行任何命令,b依然是10;
如果想让b变成11,让b和a产生一定的约束关系,就是响应式编程。
另外还有excel的公式。

MVVM

  • MVVM中的M,只用它来存放元数据。
  • ViewModel要考虑模块化,便于在不同的ViewController中复用。目前的理解:ViewModel可以和ViewController有多对多的关系。
  • ViewModel是为View服务的,它的命名和字段定义应该根据View的需要来进行。

ReactiveCocoa

缺点:

  • 学习成本,一个新人阅读代码会有难度。

优点:

  • 可以省去很多变量,不需要使用实例变量来追踪瞬时状态

思维的转变

一个场景:
一个页面API请求假如有5个,然后,有的是并行,有的是串行。如图:

API1、2、3是串行关系,1、4、5是并行关系。现在要求网络请求开始时,显示菊花,所有网络请求结束后,让菊花消失。
如果不使用rac响应式编程,我们原来的做法可能是设置3个变量:a1、a2、a3,分别表示第一行、第二行、第三行网络请求是否结束。在开始时请求时a1、a2、a3都置为YES,在每行结束时将所有变量设置为NO。并且判断是否其他变量也为NO。如果都为NO,则让菊花消失。也就是判断所有变量为NO,让菊花消失的逻辑,要出现多次。

如果使用RAC,思想将转变为:每个请求,对应一个变量。a1、a2、a3、a4、a5。然后有一个变量a的值和a1、a2、a3、a4、a5进行绑定,也就是只要当a1、a2、a3、a4、a5都为YES的时候,a为YES,然后对于a也会绑定一个事件:为NO时让菊花小时、为YES时让菊花显示。就清晰了很多。

最佳实践

什么时候绑定(取舍):

MVVM和ReactiveCocoa其实是解决两个阶段的问题。虽然配合起来使用很好,但是也不一定什么场景都配合使用,也就是说有的时候,其实只是需要抽离出ViewModel层,但是不一定非得数据绑定。例如下面场景:一个VC包含一个UITableView,数据源是一个对象数组(m_Array),m_Array可能会有以下变化:

  • 指针发生改变:例如刷新后指向新请求的网络数据解析而成的数组。
  • 增加一个元素
  • 减少一个元素
  • 某一个元素的某一个属性发生改变。
    这就会遇到以下几个问题:
  1. 每次改变都必须通过KVO能够检测到的方式来写。例如

    NSMutableArray *fromKVC = [self mutableArrayValueForKey:@"postedImagesIds"];
    [fromKVC addObject:imagePosted.imagePostedId];
    [fromKVC replaceObjectAtIndex:i withObject:imagePosted.imagePostedId];

试想我们将数组中的某个元素model1传递给了下一个VC,在这个VC中我们对model1中的那么属性进行了修改

model1.name = @"new value";

但是为了能让绑定检测到,我们需要这么写:

Model *newModel = [[Model alloc] init];
newModel.xxx = model1.xxx; // 其他没有改变的属性
....
newModel.name = @"new value";
 [fromKVC replaceObjectAtIndex:i withObject:imagePosted.imagePostedId];

也就是我们相守了绑定带来的方便,缺引入了代码上的麻烦与不干净。甚至如果不了解这套机制的人很容易不知道要这么写。

然后再想想,绑定虽然带来了方便,任何时候绑定的数据源变了,就执行相应的代码(比如刷新UITableView),我们虽然不用手动考虑什么时候执行刷新UITableView,但是也失去了主动控制的权利,假如场景中太频繁的会改变数据源,我们知道刷新UITableView也是要消耗资源的,所以本来我们可以以lazy的方式,在需要刷新的时候刷新,但是现在失去了这个主动权利了,所以要权衡。
还有一点,不使用绑定,我可以对于某一行的变化告诉UITableView之刷新这一行,如果使用绑定,往往就是有任何改变就全量刷新了。列表数据很多时也不得不考虑这件事(通过增加额外的逻辑似乎也能办到,但是还是不直观)

所以,结论就是,要看具体情形而定,不一定每次ViewModel都要通过绑定来通知变化。
目前我的做法是:

  1. 数据源是model list的,并且数据一般很多,频繁变化,一般都是应用的首页,最需要考虑体验好,内存消耗小的时候,不使用绑定。
  2. 数据源是简单的model,或者不是最最主要,数据最多的的最核心的那部分列表,可以使用绑定,好维护。

遗留问题

  1. 内存泄漏
  2. 合并信号的写法
  3. 不使用绑定的时候通过什么回调(目前采用delegate)。
  4. 有时候数据变化不想出发绑定里定义的事件
  5. 封装变化,让viewmodel更加抽象(基类)。
  6. ViewModel之间的依赖,什么场景发送消息,如何发送消息,如何实现一个消息总线。
posted @ 2017-02-20 18:00  张驰小方块  阅读(202)  评论(0编辑  收藏  举报