美文网首页
iOS组件化解决方案

iOS组件化解决方案

作者: 送我迷迭香 | 来源:发表于2019-08-02 17:53 被阅读0次

    0 起源

    出于以下原因

    1. 公司要求
    2. 业务解耦
    3. 组件易复用
    4. 组件更加黑盒
    5. 组件更好测试
    6. 更好的切割任务,明确责任

    部门要在近期开始对于组件化插件化模块化的开发方式的学习,并落地到实际开发流程当中。

    1 什么是组件化

    组件化的本质是将原先单Xcode的项目从原来的项目-目录-文件的结构基础上增加一个层级即项目-子项目-目录-文件

    名词定义:

    组件化: 组件化插件化模块化的统称

    组件:组件化后程序的基本组成单位。

    模块:稍大,较为具体的组件。比如各种控制器组件。

    1.0 组件化结构图:

    我们从下向上进行分析。

    <img src='https://ws3.sinaimg.cn/large/006tNc79gy1fvq6rxrqxmj30ku0vidhk.jpg' width=50% />

    1. 第三方库:通过CocoaPods集成的第三方库(直接集成)。
    2. 公司项目通用组件:公司根据自身情况封装的组件库,涉及了公司内部固定不变的业务,如对网络请求的加密方式(直接集成)。
    3. 业务组件:此处为封装与业务相关,且会被多个业务模块使用的通用组件。
    4. 业务模块:此处为大粒度的业务模块,如首页模块,文章详情及文章列表模块。(此处有文章,下文会展开讲解)
    5. 项目壳:仅引用业务模块,内部不包含任何的业务代码。

    1.1 组件化分级原则

    结构设计原则:下级结构是为上级结构提供服务的。只有上级结构能引用下级结构,下级结构不允许引用上级结构。同级横向引用后续分析。

    1.1.0 那么如何确定一份代码到底要如何分层?

    1. 先排除错误答案

      第三方库,公司项目通用组件:**此处代码不会因具体项目的业务而改变,因此无法写任何业务代码。

      项目壳:此处为项目壳同样不允许出现业务代码

    2. 业务模块,业务组件,业务员组件子层级

      若模块需跨多项目重用则项目不能依赖除第三方库和公司项目通用组件以外的组件。

      此处放置业务代码的基础逻辑为:在不写重复代码的前提下,代码尽量靠上。

      举个🌰:

      开始开发的时候将用户模型文件放在了业务模块-Profile组件中。后来发现业务模块-Home也需要使用用户模型此时需要将用户模型下沉到下级结构。

      举个🌰:

      开发的时候将某份代码放在了业务组件,但是在后续代码review中发现仅有一个业务模块使用了该组件。那么此时应该将该组件上浮至所需的业务模块。

      PS:开发中更换代码所属的层级会产生不必要的成本。这两个🌰其实都可以在开发初期的设计合理的分层避免。

    1.1.1 如何确定组件的粒度

    这部分涉及到程序员个人对应业务的理解,已经后续需求的预估。

    个人给出的建议是:在考虑业务独立性的情况下,进行大粒度的拆分。

    举个🌰:

    搜索页面模块,如果你认为该页面下的所有元素不会在存在任何复用。那么可以仅用一个模块完成开发。

    举个🌰:

    如果搜索页面模块搜索框已经确定了被其他页面复用,或者将来可能被其他项目复用。

    那么应该将搜索框作为一个组件,然后搜索页面模块再引用该组件。

    2 方案调研

    此阶段为了解比较社区中流行的解决方案。统计如下:

    2.0 组件解耦/通信:

    1. Route-url:

      类似http请求,通过url进行调用。

      代表:MGJRouter

      优点:简单快捷,耦合度低。

      缺点:1. 需要维护一份在线文档列出所有的url及所需参数。

      ​ 2.url对于传递参数有较大限制。UIImage,带有特殊符号的字符串等等,均无法传递

      ​ 3.注册中心需要维护一份{key:block}的映射表,常驻在内存当中

      ​ ...

      [MGJRouter registerURLPattern:@"zhejiang://post/detail/:id" toObjectHandler:^id(NSDictionary *routerParamters){
       TQDetailViewController *vc = [TQDetailViewController new];
          vc.ID = routerParamters[@"id"];
          return vc;
      }]
      
      id vc = [MGJRouter objectForURL:@"zhejiang://post/detail/1”];
      
    2. Target-Action:

      维护一个单例中间件,组件已添加中间件的分类的方式暴露自身接口。

      代表:CTMediator

      优点:编译器参与模块功能检查,无需注册。

      缺点:业务模块横向之间存在耦合。

      [[CTMediator sharedInstance] performTarget:@"TQPostModule" action:@"detail" params:@{@"id": @1}];
      
    3. Protocol-Service

      用协议包装组件整个组件所有的公开方法属性供外部调用。

      代表:BeeHive

      优点:Target-Action相同

      缺点:Target-Action相同,但需要注册,无法实现中心化。

      id<TQHomeServiceProtocol> module = [[BeeHive shareInstance] 
                                          createService:@protocol(TQHomeServiceProtocol)];
      id vc = [module home];
      

    2.1 组件集成

    1. 单项目通过文件夹进行组件分割

    2. 通过多个子项目进行组件分割

    3. 在2的基础上讲子项目打包成framework进行组件分割

    4. 使用Cocoapods进行组件分割

      组件集成使用Cocoapods+私有Spec仓库+私有Module仓库进行集成。

      使用方式参考:你真的会用 CocoaPods 吗?

    3 一些思考

    3.1 中心化的必要性

    image-20181010094856508 image-20181010094948573 v2-b62d8de4f113da8e2da767ace8772e13_r

    3.2 组件通信区别

    3.3 组件拆分逻辑的重要性

    3.4 模块的可移植性

    3.5 组件修改的多米诺效应

    3.6 主干工程无法感知模块的更新

    3.6 组件化利弊分析

    (来源自前同事 by magic-yu)

    相关文章

      网友评论

          本文标题:iOS组件化解决方案

          本文链接:https://www.haomeiwen.com/subject/sokrdctx.html