今日头条:iOS 架构设计杂谈

21,108 阅读7分钟

内容来源:2018 年 3 月 10 日,今日头条-Musically IOS端架构师任凯在“饿了么技术沙龙・第22弹 【移动专场】”进行《IOS架构设计杂谈》演讲分享。IT 大咖说(微信id:itdakashuo)作为独家视频合作方,经主办方和讲者审阅授权发布。

阅读字数:2842 | 8分钟阅读

嘉宾演讲视频及PPT回顾:suo.im/4HHwpv

摘要

本次分享将探讨iOS中的架构设计,讲解工程设计的6大原则,通过一个简单登陆界面,一步步分析开发中的MVVM框架应用。

为什么要做架构设计?

目前开发团队的人员越来越多,应用运营起来之后业务需求和功能需求日益增长,在没有良好的架构设计的情况下,维护起来会越发困难,因此架构设计是应用开发中不得不思考的问题。

这是一段非常简单的代码,它启动了App初始化了Applocaltion对象,然后分发各种事件到实现的API内。这套代码背后是RunLoop的死循环,在主线程上驱动整个App进行UI事件的处理,分发给相应的API。

如果没有API封装和UI Kit架构设计,那么在main函数内实现一个简单的按钮都是非常麻烦的。 

归根结底架构设计的目的是为了降低业务开发门槛,使业务开发更容易,使工程代码易懂易维护。

怎么做一个工程架构

代码追求

要想做工程架构首先要对代码有追求,DRY和Kiss这个两个原理相信大家对有所接触。DRY即Don’t repeat yourself,也就是不要在工程内复制粘贴;Kiss即Keep It Simple,Stupid,架构设计不是为了追求炫酷和复杂度而是要让工程架构更简洁易懂,隐藏复杂的细节提供易用的API。

六大设计原则

Solid原则,是针对面向对象的程序设计提出的,即使在反思面向对象一些问题的现在,这一原则内的很多东西也有很重要的参考意义。

单一功能原则,不要考虑在模块内实现与它不相关的功能,比如在一个类中既要处理string MD5又要处理图片的解压缩,这就是明显的违反单一功能原则的例子。再往细说,其实在方法内也不应该处理过多的事情。

开闭原则,设计模块时要考虑对扩展开发对修改封闭,简单理解就是提炼不变的逻辑,将稳定的部分封装成模块的核心逻辑,对可扩展的部分进行注入。

里氏替换原则,指的是所有的子类都可以替换父类,但是一般情况下我们是不会通过子类去破坏父类的逻辑。

接口隔离原则,对于client应该隐藏不需要的细节,隔离这些部分不去依赖它们,使API的依赖更加简洁。

依赖反转原则,指的是高层次的模块不应依赖低层次的模块,个人认为这是个伪命题,因为高层次的模块一旦依赖低层次的模块,那它就不是高层次的模块了。如果高层次模块确实需要依赖某些东西的时候,所依赖的东西应该是抽象的。

最少知识原则,开发人员在使用模块的时候,对该模块知道的越少才越好。

这六大原则其实翻来覆去都是在讲两件事情,一个是易理解的API设计,另一个是建立合理依赖关系。

基于以上的原则前人已经总结出了一些方法论,比如MVC,MVVM,Viper,这些其实是模块拆分角色设计的经验,当然这些是GUI层的,不过在其他的层面也可以有自己的角色拆分的经验。

MVVM案例

iOS MVVM实现方案

MVVM中最令我兴奋的是有ViewModel这个角色,因为ViewModel比苹果的MVC设计中的Controller更小,同时又能处理业务逻辑,当业务逻辑拆分的足够小和分散的时候,这些部分可复用的可能性更大。

ViewModel其实是View的数据层的影子,它的神奇之处在于这个影子是可以被改变然后映射到实体上。这个过程中ViewModel抽象出UI的数据,然后将这些与UI上的属性进行绑定。

GUI还有一个很重要的部分,就是ViewController。虽然我们是想打破MVC,但是苹果的UI Kit是基于MVC的设计理念,ViewController被赋予了很重要的角色,用来控制页面跳转、配置ViewModel和View的绑定。

初步设计

Login设计要想贯穿MVVM理念大致逻辑是这样的,LoginView有两个textFile并分别将它们的text部分绑定到username和password上,这样用户在UI上操作,ViewModel层的数据就会进行同步的改变。然后将LoginView的LoginButton事件在ViewModel上做处理,当LoginButton事件触发的时候,ViewModel可以抛开UI层去做一系列的事件处理。

进一步提炼

如果真的基于前面的设计去实现,而没有引入第三方辅助,就会发现这其实是非常复杂的事情。因此为了开发功能更容易,需要引入第三方或者自己去提炼一些东西。

第一个可以提炼的是Common UI,比如对于有相似样式的控件,可以提炼出共用的代码作为Common UI,达到组件复用的目的。处理完登录后要将模型共享出去,这时可以封装一个AccountManager用来向服务器换取模型,其他地方就能通过这个模型来获取token或者用户信息。

在UI Kit上做绑定并不容易,需要用ReactiveCOcoa或者RxSwift这样的框架来将View和ViewModel绑定或者模型反序列化等等。

经过这样的设计整个App的层级结构已经初步成型,最底层是App功能,在此之上是App通用业务层,这块提供可以相互使用的组件、模块。再往上的iOS通用层中其实很多东西在iOS的其他开发上都能够用到。

公司通用

通常情况下一个公司会有几个App,在App中的一些通用逻辑也可能可以给其他App使用。经过MVVM的设计ViewModel和Model已经与App的UI解耦,可以很轻松的将ViewModel往上提一个层次让整个公司去使用,这时整个架构就会多出一个公司通用业务层。

整个过程中MVVM指导了UI与业务逻辑组件拆分,UI与业务逻辑的解耦使得不同APP间的登录功能有共用的组件,通过丰富的iOS通用层组件使绑定、网络请求、数据反序列化变得更容易实现。

架构设计需要产出的重要结果是三个通用层有丰富工具、模块,使大部分业务开发可以通过组合通用层的模块工具实现。

如何能设计好模块

设计好模块首先要了解设计原则,知道什么情况下会带来糟糕的依赖,并且要坚持这些原则。还要了解常用模块设计方法,比如对MVVM有比较深入的理解就能对GUI层的逻辑做很好的拆分。最后也是最重要的一点就是不断反思改进,其实就是遇到坑的时候思考下为什么怎么坑。

架构在项目中执行

在一个项目中执行好的设计原则或者优秀的设计,首先需要建立合理的工程文件结构,知道自己封装好的组件应该放在哪里。另外还要达成团队架构设计共识,切勿闷头开发。