臧成威:解析美团客户端响应式框架 EasyReact

向作者提问
美团技术团队官方账号
查看本场Chat

2018年08月22日,周三晚20:30,美团iOS高级技术专家臧成威老师带来了主题为《美团客户端响应式框架 EasyReact 开源》的交流。以下是主持人张义整理的问答实录,记录了作者和读者间问答的精彩时刻。


内容提要:

  • 响应式编程思路是怎样的,和命令式的显著区别优势在哪里?
  • EasyReact 怎样快速入手?
  • EasyReact 下一步的发展计划是什么?
  • 以下代码是这样用吗?
  • 响应式和声明式有什么区别?美团的框架是自主的,文档注释都是中文吗?
  • 可以进入生产环境了吗?
  • 如何进行绑定操作?
  • 响应式框架如何跟组件化有机结合?
  • 在不耦合 Model 的情况下,节点如何与 Cell 关联起来,是否可以直接使用元组替代 Model?
  • 上面提到以后也可能会提供 Swift 的实现,那么相对 Swift 比较流行的 RxSwift , EasyReact 的优势是什么?

问:响应式编程思路是怎样的,和命令式的显著区别优势在哪里?

答:响应式编程是面向数据流动和传播的编程范式。犹如过程式编程的思路是将整个程序运作看成是过程的控制和参数的传递;面向对象编程的思路是将整个程序抽象成对象的属性和方法。响应式编程则把程序抽象成数据与数据间的关系。

大家可以以 Excel 等电子表格来进行类比,熟练使用电子表格的同学都可以将简单的办公需求转换成电子表格来解决实际问题。其做法就是利用表格的各个单元格的关系来进行“编程”,最终在部分单元格中输入数据源,在部分单元格中得到结果。响应式编程的意图也是如此,我们将程序中的数据封装起来形成可以被传播的媒介(信号或者节点),然后将这些传播媒介相互的关系描述出来,在最终数据敏感的部分取出。

响应式编程的这种方式属于声明式编程的一种,与命令式相对应。然而在非纯粹的响应式编程语言下,响应式仍然是由命令式编程来实现的。其本质在于编程的思路与侧重点不同。命令式编程的侧重点在于描述动作对状态的影响。而响应式则关心数据之间的联系,当一个数据变化的时候,另外的数据应该如何变化。实际上的开发中或多或少的利用了响应式的部分思路,例如通知,KVO。所以响应式与大家并非陌生。命令式中最大的问题在于过多的状态量在不同的命令进行修改,会导致异步情况下难以控制状态量。响应式则将状态的关注侧和改变侧进行隔离,使得业务解除耦合。


问:EasyReact 怎样快速入手?

答:好的思路少不了好的例子,为此 EasyReact 在开源过程中为大家提供了丰富的文档和注释。可以在 Github 的项目主页 https://github.com/meituan/EasyReact 中查看到。

使用 EasyReact,大家可以进行一个简单的思维转换。那就是把原来组件设计里面的属性都使用EZRNode<__YourType *> *EZRMutableNode<__YourType *> *来包装起来。一旦这样做,就相当于给原来的属性自动加上了 KVO 和 KVC 功能。另外一个好处就是当我们需要一个属性根据另一个属性而变化的时候,就可以利用 EasyReact 提供的各种转换功能进行传递了。

https://github.com/meituan/EasyReact/blob/master/Documents/Chinese/BasicOperators.md 为大家提供了诸多了例子,大家可以参阅。


问:EasyReact 下一步的发展计划是什么?

答:专注过 EasyReact 项目的同学不难发现很多以 Easy 开头的附属库被其依赖,EasyReact 只是我们整体 MVVM 架构中的一环,后续会有 EasyMVVM、EasyAction 等库将更多的内容提供给大家,另外由于 EasyReact 思路的平台无关性也会提供 JavaScript、Swift、Java 等多种语言实现供各个平台使用,还有为了更好使用还会提供很多的辅助功能,例如节点调试功能,详细的内容大家可以参考 GMTC 2018 (链接: https://pan.baidu.com/s/1f5pdjWOI1Vq_4AwLp2hDeg 密码: ardq)的分享。


问:以下代码是这样用吗?

NSMutableArray *fuCardsArray = [NSMutableArray array];
         for (NSDictionary *info in array)
         {
             EZTuple2<NSString *, NSNumber *> *fuCardTuple = EZTuple(info[@"cardNo"], [NSNumber numberWithInteger:[info[@"balance"] integerValue]]);
             [fuCardsArray addObject:fuCardTuple];
         }
         self.fuCardsArrayNode.value = fuCardsArray;
         if (fuCardsArray.count > 0) {
             self.fuCardsSelectArrayNode.value = @[fuCardsArray[0]];
         }

答: EZRMutableNode 可以当做一个容器,所以上面的使用是正确的,想要取得容器中的值可以通过 self.fuCardsArrayNode.value 或者 [self.fuCardsArrayNode listenedBy:__someone] 来得到


问:响应式和声明式有什么区别?美团的框架是自主的,文档注释都是中文吗?

答:前面第一个问题为大家解答了两者的区别。EasyReact 里面的代码注释是英文的,而所有的文档都是中英文版本的,另外 EasyReact 提供了丰富的测试,大家也可以在 https://github.com/meituan/EasyReact/tree/master/Example/Tests 代码下看到各个方法的使用用例,任何对代码的问题都可以通过 Github 的 issue 来提给我们,我们会很快解答 https://github.com/meituan/EasyReact/issues


问:可以进入生产环境了吗?

答:目前 EasyReact 现集成与美团 iOS App 中,账户、清单、城市列表等功能均有使用,我们的内信也有部分使用。


问:如何进行绑定操作?

答:绑定是一个很泛化的概念,在 MVVM 框架中经常提及,EasyReact 是面向数据流的一个基础库,可以很好的完成数据传递的部分,我们可以这样的看待绑定,就是 业务逻辑-》数据节点-》视图逻辑,或者 视图逻辑-》数据节点-》业务逻辑,亦或是 视图逻辑《-》数据节点《-》业务逻辑,以 EasyReact 来定义就是一个 EZRNode 的监听行为和设置行为,另外双向传递会有回声问题,也就是 A <-> B 同步,会出现 A 变化通知 B,B 变化又通知回 A 的现象。在 EasyReact 的 Node 内部是自动抑制回声的,而外部例如 TextField 与一个 Node 绑定就会存在外部回声,可以通过传递 context 来解决,也就是 [someNode setValue:v context:c]。


问:响应式框架如何跟组件化有机结合?

答:组件化是一种工程实践,响应式框架与组件化结合的部分就在于给与组件化一个更通用的依赖关系,OOP 的组件以类的属性和方法提供功能,响应式组件可以以数据节点提供功能,允许其他组件感知变化的可以使用 EZRNode,允许其他组件进行修改则使用 EZRMutableNode。后续开源的 EasyAction 会为大家提供类似类的方法这样的行为库,使得行为这种抽象也能够响应起来。


问:在不耦合 Model 的情况下,节点如何与 Cell 关联起来,是否可以直接使用元组替代 Model?

答: MVVM 中颇具争议的就是 Model 层级的定义,一般会有胖 Model 和瘦 Model 两种理解,美团 Easy 框架中对于 Model 的理解是胖 Model。一个 Model 就负责一个业务,通常理解的瘦 Model 实际上是 entity,EasyReact 可以很容易的将 Model 的逻辑与视图的逻辑解耦开来,Model 层对外提供可以监听的数据节点 EZRNode 以及可以设置的数据节点 EZRMutableNode,Model 自身完成对数据的获取加工,视图部分来监听数据的变化渲染视图,后面开源的 EasyMVVM 里面有辅助工具库专门帮助 Cell 和 viewModel 的绑定。

enter image description here

整体架构大概这样。

enter image description here

绑定的实例代码就像这样。

对于瘦 Model,或者胖 Model 中的 entity,可以用 EasyTuple https://github.com/meituan/EasyTuple 的命名化元组来完成。


问:上面提到以后也可能会提供 Swift 的实现,那么相对 Swift 比较流行的 RxSwift , EasyReact 的优势是什么?

答: RxSwift 是函数响应式编程的范式,大家在使用的过程中需要熟知函数式的一些特点,例如闭包、不变量等,而 EasyReact 是纯粹的响应式编程,只需要关注值的设置与订阅就可以很快掌握,最大的优势就在于学习成本会比较低。

可以提前透露下 Swift 的响应功能,例如我们希望 a 对象和b 对象每当改变的时候,就调用 a.p(b)方法,在函数式思路中必要的逻辑就是combine a和b 的信号,得到新的节点,而 EasyReact Swift 会采用类似 let aNode = Node.mutable(a) ; aNode.apply(Aclass.p, b)来直接得到返回值的节点,只要 aNode 或者 b 有 setValue,返回的节点就会改变。

大家可以在项目中尝试使用下,积累更多的问题,都可以直接联系我或者给 Github 的项目发 issue,EasyReact 并没有入侵性,可以放心的小规模使用。


本文首发于Gitchat,未经授权不得转载,转载需要与GitChat联系。

倾情走开
想不通为啥在有RxSwift这种现有的,用着挺爽的框架情况下,又另起炉灶。不过拓扑图这个的确是让人眼神一亮,666。个人感觉Rx的缺点只有1个半。一个缺点是资源管理的方式挺麻烦的,容易出现信号没释放,提前释放之类的情况;半个缺点是堆栈层次太多了,打断点的方式调试起来不友好,这个Rx本身提供了专门的调试函数。其他的说什么函数式编程是缺点都是虚的,个人感觉函数式比响应式更好入门。靠学习就能解决的缺点都算不上缺点。
微信扫描登录