iOS八股文之 组件化

一、组件化是啥

  • 在软件代码设计中,有一个非常重要的判断好坏的标准是 "高内聚、低耦合";那么组件化就是这个标准非常好的一个实践。
  • 所谓高内聚,对应组件化纵向的分层以及每层基于特定功能进行组件拆分,每个组件专注于特定功能;所谓低耦合,组件间通过标准化接口通信,避免直接依赖;
  • 组件化的核心挑战是组件间通信和依赖管理;

二、组件化的好处有啥

  • 解耦代码:避免 "牵一发而动全身"(如修改一个功能导致多个模块报错);
  • 团队并行开发:不同团队负责不同组件,通过接口约定协作,减少代码冲突;
  • 按需编译:仅编译当前开发的组件,大幅提升编译速度;
  • 功能复用:组件可在多 App 间复用(如车控组件同时用于不同子品牌App);

三、组件化方案收集

1. URL 路由式(蘑菇街 MGJRouter 为代表)

  • 核心思想:通过 "URL 字符串" 作为通信介质,路由中心解析 URL 并转发到目标组件。
  • 实现步骤:
    • 注册阶段:组件在初始化时,向路由中心注册 URL 与处理函数的映射(如[router registerURLPattern:@"mgj://pay" handler:^(NSDictionary *params) { ... }]);
    • 调用阶段:调用方通过 URL 发起请求([router openURL:@"mgj://pay?amount=100" completion:^(id result) { ... }]);
    • 路由分发:路由中心解析 URL 的 "schema"(如mgj)、"path"(如/pay)和参数,找到对应的 handler 执行,并将结果通过 completion 返回。
  • 核心技术:
    字符串解析(URL 参数转字典);
    注册表(通常用NSDictionary存储 URL→handler 的映射);
    支持 Block 回调实现双向通信。
  • 优缺点:
    优点:接入简单、无编译期依赖(适合快速落地);
    缺点:参数类型不安全(需手动转换)、URL 管理成本高(易冲突)、不适合复杂对象传递(URL 仅支持基本类型)。

2. 协议接口式(滴滴 DDComponentManager 为代表)

  • 核心思想:通过 "协议(Protocol)" 定义组件接口,组件实现协议并注册,调用方依赖协议而非实现。
  • 实现步骤:
    • 定义协议:在公共模块(如CommonModule)中定义协议,声明组件提供的功能(如@protocol PaymentService - (void)payWithOrder:(Order *)order; @end);
    • 组件实现协议:支付组件实现协议(@interface PaymentServiceImpl : NSObject ... @end);
    • 注册服务:组件启动时,向 "服务中心" 注册协议与实现类的映射([ServiceManager registerService:@protocol(PaymentService) withImplClass:[PaymentServiceImpl class]]);
    • 调用服务:调用方通过服务中心获取协议实现(id payment = [ServiceManager getService:@protocol(PaymentService)]; [payment payWithOrder:order])。
  • 核心技术:
    协议(Protocol)作为接口契约;
    服务中心(单例):管理协议→实现类的映射表,通过NSClassFromString反射创建实例;
    依赖注入:服务中心可自动实例化实现类,或由组件手动注册实例。
  • 优缺点:
    优点:类型安全(编译期校验)、支持复杂对象传递、依赖关系清晰;
    缺点:需维护协议层(增加代码量)、初期接入成本较高。

3. Target-Action 式(基于反射,蘑菇街后期优化方案)

  • 核心思想:通过 "目标类(Target)" 和 "方法(Action)" 的字符串反射调用,避免直接依赖。
  • 实现步骤:
    • 定义 Target 类:每个组件提供一个Target_XXX类(如支付组件的Target_Payment),封装对外接口(- (void)action_payWithParams:(NSDictionary *)params);
    • 调用方通过中间层反射调用:调用方不直接依赖Target_Payment,而是通过中间层(如Router)传递 "Target 名" 和 "Action 名"([Router invokeTarget:@"Payment" action:@"pay" params:@{@"amount": @100}]);
    • 中间层反射执行:Router通过NSClassFromString(@"Target_Payment")创建实例,再通过performSelector:withObject:调用action_payWithParams:方法。
  • 核心技术:
    运行时反射(NSClassFromString、performSelector);
    参数统一用NSDictionary传递(兼容任意类型);
    中间层封装反射逻辑,避免调用方直接写反射代码。
    优缺点:
  • 优点:无需协议层,组件解耦彻底;
    缺点:类型不安全(字符串拼写错误编译期不报错)、反射有一定性能损耗(可通过缓存优化)。
4. 组合式(URL + 协议 + 依赖注入,美团 / 阿里方案)

大型项目通常采用组合式方案,兼顾多种场景:

  • 页面跳转:用 URL 路由(简单直观);
  • 服务调用:用协议接口(类型安全);
  • 参数传递:结合依赖注入(自动解析复杂参数);
  • 生命周期管理:增加组件管理器,统一处理初始化、降级、销毁。

四、组件化的其他关键技术点

  1. 依赖管理
    私有 Pod:通过 CocoaPods 的私有仓库管理组件,组件间通过podspec声明依赖(如 A 组件依赖基础组件BaseModule);
    源码依赖控制:禁止直接#import其他组件的非公开头文件,仅允许依赖公共接口层(协议 / 中间件)。
  2. 资源管理
    组件私有资源:每个组件的图片、xib 等资源放在独立目录,通过bundle管理(如PaymentComponent.bundle);
    资源路由:通过 "资源 URL"(如payment://image/pay_btn.png)访问组件资源,避免重名冲突。
  3. 组件生命周期
    初始化:通过+load或组件管理器的setup方法,在 App 启动时初始化组件(注册路由 / 服务、预加载数据);
    按需加载:非核心组件(如客服)可延迟初始化,在首次调用时再加载,减少启动时间;
    降级策略:组件加载失败时(如网络错误),执行降级逻辑(如显示默认页面)。
相关推荐
大熊猫侯佩3 小时前
Thread.sleep 与 Task.sleep 终极对决:Swift 并发世界的 “魔法休眠术” 揭秘
ios·swift·apple
大熊猫侯佩3 小时前
【大话码游之 Observation 传说】下集:破咒终局了,天眼定乾坤
ios·swift·apple
大熊猫侯佩4 小时前
【大话码游之 Observation 传说】中集:仙流暗涌,计数迷踪现
ios·swift·apple
大熊猫侯佩4 小时前
寥寥几行代码实现 SwiftUI 超丝滑弹窗转场动画
ios·swiftui·swift
2501_916007474 小时前
iOS文件管理工具深度剖析,从系统沙盒到跨平台文件操作的多工具协同实践
android·macos·ios·小程序·uni-app·cocoa·iphone
青茶3604 小时前
iPhone苹果手机拍的照片默认是heic如何换成jpg格式
ios·智能手机·手机·iphone
请叫我飞哥@4 小时前
Apple授权登录开发流程
ios·swift