APP架构和模块化 组件化

框架是一个APP的骨骼,核心,一个项目的所有功能以及以后的迭代都是在此基础上进行的,它是开展一个项目的至关重要的一步。如果这一步做的不好,会导致结构散乱、阅读性和扩展性差,影响开发效率甚至导致代码重构

APP主要做哪些事情

调用网络API

页面展示

数据的本地持久化

动态部署方案

收集用户数据,给产品和运营提供参考

合理地组织各业务方开发的业务模块,以及相关基础模块

每日app的自动打包,提供给QA工程师的测试工具

架构原则:易读性、易维护性、易扩展性

常见的分层架构:视图层、业务层、网络层、数据层

所谓好架构

有严格的代码规范,结构目录清晰,功能模块分类明确

注释统一明确,有一致规范

避免复杂的依赖关系,确保代码的高封装性和高复用性,减少冗余代码

没有横向依赖,尽可能少的跨层访问

对业务方该限制的地方有限制,该灵活的地方要给业务方创造灵活实现的条件

易测试,易拓展

接口少,接口参数少

低内存,高性能

提高模块化程度,增加组件粒度

项目目录结构

1. 应用入口(AppDelegate)

AppDelegate是应用的代理,应用级的事件都委托它处理,包含启动退出、推送等事件,以及IM、支付等第三方的回调,这使得AppDelegate内代码庞大,错综复杂,十分不利于阅读和维护,因此可以新增了一个AppDelegate+AppService类别,用来处理生命周期之外的业务,AppDelegate作为事件入口,具体实现直接调用类别里的方法,只为更清晰

2. 功能模块(Modules)

Modules包含了应用内的功能模块,一般根据底部Tab栏划分并关联实体文件夹,根据需求也可以增加Resource和Service文件夹,Service封装数据请求,VC里调用拿数据即可;至于Resource为什么在这,我认为当功能模块层级较多时,每个大功能模块都对应许多资源,对应到模块内用起来方便;当然也可以放到最外层的Resource文件夹里,建立对应的模块名称,在这儿我是选择把公共的放到最外层Resource里,功能相关的放到模块里的Resource文件夹内,只为更清晰;

3. 管理模块(Manager)

Manager的定义是全局基础服务,通常使用类方法或者单例来实现,主要包含对应用、用户的管理和服务,例如网络状态监听,广告页应用介绍页等;用户快速登录退出操作以及登录状态的获取等

4. 工具类(Utils)

Utils文件夹内主要包含全局通用工具,来源于对三方框架的二次封装,或是自己写的工具类。在这个项目里,我封装了带AES加密网络请求工具,全局Toast提示,广告页等

5. 基类(Base)

Base文件夹用来存放项目的基类,基类作用包含一些定制化的内容,例如页面样式,空数据页面等,使用基类来实现,可以统一控制,利于维护,减少冗余

6. 分类(Category)

对系统类、自定义类增加的类别都放在这里

7. 宏定义、头文件(Define)

全局宏顾名思义是定义了一些全局通用宏、枚举

一般是这几种:工具宏定义(UtilsMacros):比如获取屏幕宽高,系统版本,颜色赋值,数据类型验证等

接口宏定义(URLMacros):定义服务器接口地址以及环境开关

枚举(Enumerate):全局的枚举

8. 第三方库(ThridParty)

第三方文件夹放一些第三方的类库和对第三方封装,比如第三方登录、支付、IM等(静态库)

9. 资源文件(Resource)

主要是各种文件,json、xml、dat、图片,视频,声音等

10. 支持文件(Supporting Files)

主要放 PCH,Assets.xcassets,LaunchScreen.storyboard,Info.plist,main.m等系统文件

11. Pods(管理第三方库)

CocoaPods是iOS项目的依赖管理工具,开发iOS项目不可避免地要使用第三方开源库,CocoaPods的出现使得我们可以节省设置和第三方开源库的时间

模块化

就是将一个现有的工程,拆分成一个个可独立编译的子模块的过程,同时,需要提供一种机制,让各个模块间可以相互调用通信

各模块间通过中介者Mediator通信,使得各个模块间没有直接的引用。而这,也就是模块化思想的核心,这也延伸出了一个问题,Mediator 必须知道每一个模块的存在,这就在模块和Mediator间产生了强耦合

业界给出了两种方式:

1. 运用OC特有的语言机制,就是runtime反射调用。

2. 设计注册机制,每一个模块主动向Mediator注册自己,在Mediator中统一通过抽象的Class类型来管理这些模块。用户通过模块对应的key向Mediator索要对应的模块,然后在Mediator外部自行调用模块的功能

这两种方式,都可以使得Mediator不再关心具体的模块类型,使得Mediator的实现与模块解耦

CTMediator的核心思路

1.CTMediator核心,负责runtime反射的核心实现,不需要引入其他模块任何内容

2,CTMediator的Category们,这些分类是跟模块走的,有几个模块,就应该有几个Category。Category用于告诉调用者该模块可以提供哪些功能,在CTMediator库中,所提供的这些功能被称为action。Category会调用CTMediator核心的runtime接口,将任务发送到对应的target;为了能够让CTMediator Category中能够真正调用到对应模块的功能,每个模块还会提供一个对应的target。target和模块是强耦合的,target会直接引用模块中的类型和接口

所谓基于注册的模块化方案,核心思想是:在Mediator中,维护一个key-vaule形式的字典。模块所提供的所有服务(或称功能),作为key,而其真正提供服务的模块对象,则作为vaule。当客户需要特定服务时,只需要向Mediator输入对应的key,便可以得到其对应的服务对象;Service则表示该模块能够对外提供的服务,Service应该是从属与Module的

基于注册的方案也有其优点:因为所有的模块都被注册到Mediator中,因此对于一些模块关心的系统或自定义事件,在Mediator中可以很方便的传递给每个模块。

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容