iOS组件化详解
一、为什么要做组件化开发?
在 iOS 项目迭代过程中,随着业务复杂度提升、团队规模扩大,传统单体架构会逐渐暴露以下问题:
- 代码耦合严重:模块间直接依赖(如 #import "XXViewController.h"),改一处动全身,维护成本高;
- 团队协作低效:多人开发同一仓库易冲突,代码合并成本高;
- 编译速度慢:单工程代码量过大,每次编译需全量处理,耗时久;
- 复用性差:功能模块无法单独抽离复用(如登录模块在多 APP 中重复开发);
- 测试成本高:单模块修改需全量回归测试,影响迭代效率。
组件化的核心目标是 解耦 :将项目拆分为独立、可复用的组件,通过 “中间件” 实现组件间通信,解决上述问题。
二、iOS 组件化如何分层?
组件化架构通常分为 5 层(自底向上),每层职责清晰、依赖单向(上层依赖下层,禁止反向依赖):
层级 | 职责 | 示例组件 |
---|---|---|
基础层 | 提供全局通用能力,不依赖任何上层模块 | 网络(AFNetworking、Alamofire)、存储(FMDB)、工具类(Category)、基础 UI 组件(与业务无关的) |
业务基础层 | 封装跨业务的通用能力,依赖基础层,不依赖具体业务 | 登录、支付、用户信息管理、埋点统计 |
业务组件层 | 拆分独立业务模块(按功能 / 业务线),依赖基础层和业务基础层,内部高内聚 | 首页、购物车、订单、个人中心 |
中间件层 | 负责组件间通信(路由跳转、方法调用),解耦组件依赖 | CTMediator、URLNavigator、ARouter |
壳工程 | 整合所有组件,负责配置环境、启动页、根控制器设置,无业务逻辑 | Main Project(仅包含配置文件和组件注册) |
三、CTMediator 的 OC 与 Swift 实践(组件间通信)
CTMediator 是基于 “Target-Action” 模式的组件化中间件,通过运行时(OC)或桥接(Swift)实现组件间 “无依赖调用”。其核心原理:调用方通过中间件(CTMediator)发送 “指令”,中间件找到目标组件的 “Target” 类,执行对应的 “Action” 方法。
3.1. OC 实践代码
假设场景:“订单组件” 调用 “支付组件” 的支付功能。
(1)中间件 CTMediator(基础类,全局唯一)
objective-c
// CTMediator.h
#import <UIKit/UIKit.h>
@interface CTMediator : NSObject
+ (instancetype)sharedInstance;// 支付组件调用方法(中间件声明)
- (void)payWithOrderId:(NSString *)orderId callback:(void(^)(BOOL success))callback;
@end// CTMediator.m
#import "CTMediator.h"
#import <objc/runtime.h>@implementation CTMediator
+ (instancetype)sharedInstance {static CTMediator *instance;static dispatch_once_t onceToken;dispatch_once(&onceToken, ^{instance = [CTMediator new];});return instance;
}// 调用支付组件的支付方法(通过Target-Action调用)
- (void)payWithOrderId:(NSString *)orderId callback:(void(^)(BOOL success))callback {// Target_Pay:支付组件的Target类(约定命名:Target_+组件名)// action_payWithOrderId:callback::支付组件的Action方法(约定命名:action_+方法名)Class targetClass = NSClassFromString(@"Target_Pay");id target = [[targetClass alloc] init];if ([target respondsToSelector:@selector(action_payWithOrderId:callback:)]) {[target performSelector:@selector(action_payWithOrderId:callback:) withObject:orderId withObject:callback];}
}
@end
(2)支付组件(业务组件层)的实现(Target-Action)
objective-c
// Target_Pay.h(仅组件内部可见,不对外暴露)
#import <UIKit/UIKit.h>
@interface Target_Pay : NSObject
// 支付Action(参数与中间件声明一致)
- (void)action_payWithOrderId:(NSString *)orderId callback:(void(^)(BOOL success))callback;
@end// Target_Pay.m
#import "Target_Pay.h"
#import "PayService.h" // 组件内部的支付逻辑@implementation Target_Pay
- (void)action_payWithOrderId:(NSString *)orderId callback:(void(^)(BOOL success))callback {// 调用组件内部的支付逻辑[[PayService shared] pay:orderId completion:^(BOOL success) {if (callback) callback(success);}];
}
@end
(3)调用方(如订单组件)使用
objective-c
// 订单组件中调用支付,无需#import "PayService.h"或"Target_Pay.h"
#import "CTMediator.h"// 点击支付按钮
- (void)onPayClick {NSString *orderId = @"ORDER_123";[[CTMediator sharedInstance] payWithOrderId:orderId callback:^(BOOL success) {if (success) {NSLog(@"支付成功");} else {NSLog(@"支付失败");}}];
}
3.2. Swift 实践代码(需兼容 OC 的 CTMediator)
Swift 组件需通过@objc
暴露给 OC 中间件,核心是 “Swift 协议 + Target-Action”:
(1)中间件扩展(Swift 中调用 CTMediator)
// CTMediator+SwiftExtension.swift
import UIKitextension CTMediator {// Swift中声明支付调用方法func pay(with orderId: String, callback: @escaping (Bool) -> Void) {// 调用OC的Target-Action(注意参数转换)self.performSelector(inBackground: NSSelectorFromString("payWithOrderId:callback:"), with: orderId, with: callback)}
}
(2)Swift 支付组件的 Target 实现
// Target_Pay.swift(需@objc暴露给OC)
@objc(Target_Pay) // 必须指定OC类名,否则CTMediator找不到
class Target_Pay: NSObject {// Action方法需@objc,参数匹配@objc func action_payWithOrderId(_ orderId: String, callback: @escaping (Bool) -> Void) {// 调用Swift支付逻辑PayService.shared.pay(orderId: orderId) { success incallback(success)}}
}// 支付逻辑(组件内部)
class PayService {static let shared = PayService()func pay(orderId: String, completion: @escaping (Bool) -> Void) {// 模拟支付请求DispatchQueue.global().asyncAfter(deadline: .now() + 1) {completion(true)}}
}
(3)Swift 调用方(如订单组件)
// 订单组件中调用
class OrderViewController: UIViewController {func onPayClick() {let orderId = "ORDER_456"CTMediator.sharedInstance().pay(with: orderId) { success inprint("支付结果:\(success)")}}
}
四、组件化与工程化、插件化的区别和优势
概念 | 核心目标 | 技术手段 | 优势 | 适用场景 |
---|---|---|---|---|
组件化 | 拆分模块,解决代码耦合,提升协作效率 | 静态拆分模块(编译期整合),通过中间件通信(CTMediator) | 解耦彻底、编译速度快、团队协作高效、模块可复用 | 大型 APP、多团队协作、业务稳定 |
工程化 | 规范开发流程(构建、测试、部署等),提升效率 | 自动化工具(Jenkins、Fastlane)、代码规范(ESLint)、CI/CD 流程 | 减少人为操作、标准化流程、降低出错率 | 所有项目(基础保障) |
插件化 | 动态加载模块(运行时),解决包体积和动态更新问题 | 动态库(.framework)、反射加载、沙盒隔离(如微信小程序) | 按需加载、减小包体积、支持动态更新(无需发版) | 模块频繁更新、包体积敏感场景 |
组件化的独特优势:
- 相比工程化:工程化是 “流程规范”,组件化是 “架构设计”,前者为后者提供落地保障;
- 相比插件化:组件化是 “静态拆分”(编译期整合),兼容性更好(无动态加载风险),适合业务稳定的大型项目;插件化是 “动态加载”,适合需频繁更新的场景,但实现复杂且受 iOS 审核限制(动态库可能被拒)。
总结
组件化是大型 iOS 项目解决耦合、提升协作效率的核心方案,通过分层设计和 CTMediator 等中间件实现模块解耦;其与工程化(流程规范)、插件化(动态加载)定位不同,需根据项目规模和业务需求选择。