iOS程序架构
最主要的目的在于减少代码量,提高复用度,降低耦合度,方便后期修改。结构清晰,方便测试。
- 第一步:搞清楚要解决哪些问题,并找到解决这些问题的充要条件
你必须得清楚你要做什么,业务方希望要什么。而不是为了架构而架构,也不是为了体验新技术而改架构方案。减少充要条件。搞清楚对于业务方而言的真正充要条件很重要!这决定了你的架构是否足够易用。另外,传的参数越少,耦合度相对而言就越小,你替换模块或者升级模块所花的的代价就越小。
- 第二步:问题分类,分模块
- 第三步:搞清楚各问题之间的依赖关系,建立好模块交流规范并设计模块
关键在于建立一套统一的交流规范。- 第四步:推演预测一下未来可能的走向,必要时添加新的模块,记录更多的基础数据以备未来之需
- 第五步:先解决依赖关系中最基础的问题,实现基础模块,然后再用基础模块堆叠出整个架构
- 第六步:打点,跑单元测试,跑性能测试,根据数据去优化对应的地方
总而言之就是要遵循这些原则:自顶向下设计(1,2,3,4步),自底向上实现(5),先测量,后优化(6)。
什么样的架构叫好架构?
代码整齐,分类明确,没有common,没有core
不用文档,或很少文档,就能让业务方上手
思路和方法要统一,尽量不要多元
没有横向依赖,万不得已不出现跨层访问
对业务方该限制的地方有限制,该灵活的地方要给业务方创造灵活实现的条件
易测试,易拓展
保持一定量的超前性
接口少,接口参数少
高性能
View层
当我们开始设计View层的架构时,往往是这个App还没有开始开发,或者这个App已经发过几个版本了,然后此时需要做非常彻底的重构。我们在这时候必须清楚认识到:View层的架构一旦实现或定型,在App发版后可修改的余地就已经非常之小了。因为它跟业务关联最为紧密,所以哪怕稍微动一点点,它所引发的蝴蝶效应都不见得是业务方能够hold住的。
View代码结构的规定
不要在viewDidLoad里面初始化你的view然后再add,这样代码就很难看。在viewDidload里面只做addSubview的事情,最后在viewDidAppear里面做Notification的监听之类的事情。至于属性的初始化,则交给getter去做。
常情况下ViewController里面一般是不会存在private methods的,这个private methods一般是用于日期换算、图片裁剪啥的这种小功能。这种小功能要么把它写成一个category,要么把他做成一个模块,哪怕这个模块只有一个函数也行。ViewController基本上是大部分业务的载体,本身代码已经相当复杂,所以跟业务关联不大的东西能不放在ViewController里面就不要放。另外一点,这个private method的功能这时候只是你用得到,但是将来说不定别的地方也会用到,一开始就独立出来,有利于将来的代码复用。
在iOS开发领域中,怎样才算是MVC划分的正确姿势?
M应该做的事:
给ViewController提供数据
给ViewController存储数据提供接口
提供经过抽象的业务基本组件,供Controller调度
C应该做的事:
管理View Container的生命周期
负责生成所有的View实例,并放入View Container
监听来自View与业务有关的事件,通过与Model的合作,来完成对应事件的业务。
V应该做的事:
响应与业务无关的事件,并因此引发动画效果,点击反馈(如果合适的话,尽量还是放在View去做)等。
界面元素表达
目录结构:
第一种
AppDelegate 这个目录下放的是AppDelegate.h(.m)文件,是整个应用的入口文件,所以单独拿出来。
Macro 这个目录下放了整个应用会用到的宏定义(把宏定义在.h中放在这个目录中)VendorMacro.h 里放一些第三方常量
Models 这个目录下放一些与数据相关的Model文件,General 这个目录放会被重用的Views/Classes和Categories
Vendors 这个目录放第三方的类库/SDK,如UMeng、WeiboSDK、WeixinSDK等等。
Helpers 这个目录放一些助手类,文件名与功能挂钩。助手类的主要作用是帮助Controller瘦身,也可以提供一定程度的复用。自己封装可复用的类等。
Sections 这个目录下面的文件对应的是app的具体单元,如导航、瀑布流等等。
Resources 这个目录下放的是app会用到的一些资源,主要是图片。
Cocoapods 业务无关的类库可以通过 Cocoapods 来方便地管理,如SDWebImage, Reachability等等。还有一些是多个应用都会用到的基础模块,比如HBAPI、HBSNS 、HBFoundation(HB为公司名首字母)等等,可以建一个私有的git repo,然后加到podfile中,这样如果HBAPI有更新,只需要pod update一下就行了。
主目录按照业务分类,内目录按照模块分类
主目录按照模块分类,内目录按照业务分类
VPBD
ViewController(View):管理View的层次结构、生命周期、一些组合过的View。
ViewModel:负责转换View需要的数据格式。
Presenter:显示View、ViewController的逻辑。
Router(Wireframe):页面跳转逻辑。
Business:核心业务逻辑,复用性很高。
Model:基本数据模型,根据业务来定义。
DataSource:对于数据的抽象,对于Business层而言,不需要知道它是从网络、数据库还是缓存中得到的。
MVVM 模式下iOS项目目录结构
一、MVVM 模式介绍
MVVM 是 Model-View-View Model 的缩写,MVVM 听起来好像很复杂的样子,但它本质上就是MVC 的改进版。MVVM 就是将其中的View 的状态和行为抽象化,让我们将视图 UI 和业务逻辑分开。当然这些事 ViewModel 已经帮我们做了,它可以取出 Model 的数据同时帮忙处理 View 中由于需要展示内容而涉及的业务逻辑。在 iOS 中使用 MVVM 可以将 ViewController 中处理 Mode 的业务逻辑全部交由 ViewModel,让 ViewController 不再显的特别臃肿。
MVVM模式是通过下面三个核心组件组成,每个都有它自己所要处理的事情:
Model -数据模型
View – 用来将Model 的内容显示出来
ViewModel - 扮演“View”和“Model”之间的使者,帮忙处理 View 的业务逻辑
- 低耦合。视图(View)可以独立于Model变化和修改,一个ViewModel可以绑定到不同的"View"上,当View变化的时候Model可以不变,当Model变化的时候View也可以不变。
- 可重用性。你可以把一些视图逻辑放在一个ViewModel里面,让很多view重用这段视图逻辑。
- 独立开发。开发人员可以专注于业务逻辑和数据的开发(ViewModel),设计人员可以专注于页面设计。
- 可测试。界面素来是比较难于测试的,而使用MVVM的一大好处是我们可以很容易对 ViewModel 进行单元测试
二、项目目录结构
一个合理的项目目录结构首先应该是让人一目了然的,让人一眼看上去就能大概了解目录的职责,了解每个文件夹下的内容是做什么的,而且容易应对新的改变方便后续添加功能或者扩展。要达到以下两个目的:
1)使项目更适合于团队开发,能够降低耦合、便于任务的划分和代码的整合管理。
2)使项目能够积累出更多可复用的代码和架构。
这个结构会在不断遇到问题解决问题的过程中权衡、进化,在这个过程最重要的是能够保持:
1)主干简洁。主干上防止过度划分,过度划分会让代码放在这个目录下也可以,放在另一个目录下好像也行,容易混乱。
2)分支开放。不对过于细节的分支做严格规范,可以发挥大家的灵活性和创造性。
Define —— 用于存放些宏(#define)。
Models —— 用于存放模型类。如:BaseModel.h,CollectionModel.h
NetworkManager —— 用于存放网络请求类
Resources —— 用于存放资源 例如xib,storyboard,图片,plist,音频,视频
Util —— 用于存放可重用的分类Category和扩展或者工具类Tools,比如数据正则匹配等。能复用的视图Views
Vendors —— 用于存放第三方框架或者第三方SDK文件
View —— 用于存放视图类
ViewControllers —— 用于存放视图控制器类,也就是View层。
ViewModel —— 用于存放视图模型类,及处理 View 和 Model 之间的业务逻辑和网络请求。
Config:就是工程的配置文件,用于放置程序的一些配置,UI高度,方便统一修改。
整体项目的运行流程是:每层之间的交互是用Block的形式来实现的。
ViewController->向ViewModel请求数据->ViewModel->向网络请求数据->需要数据解析类型负责解析
开发流程
在拿到设计图后,就可以针对设计图抽离出可复用的Classes/Views,考虑一下某个效果的具体实现,使用合适的设计模式来避免大量的if/else嵌套,等等。所以前期一定要做好充足的准备工作。
ViewController里面:
@property
pragma mark - life cycle
生命周期
viewDidLoad
pragma mark - UItableViewDelegate
pragma mark - CustomDelegate
自定义委托
pragma mark - event response
事件响应
pragma mark - private methods
私有方法