iOS组件化详解
一、为什么要做组件化开发?
在 iOS 项目迭代过程中,随着业务复杂度提升、团队规模扩大,传统单体架构会逐渐暴露以下问题:
- 代码耦合严重:模块间直接依赖(如 #import \"XXViewController.h\"),改一处动全身,维护成本高;
- 团队协作低效:多人开发同一仓库易冲突,代码合并成本高;
- 编译速度慢:单工程代码量过大,每次编译需全量处理,耗时久;
- 复用性差:功能模块无法单独抽离复用(如登录模块在多 APP 中重复开发);
- 测试成本高:单模块修改需全量回归测试,影响迭代效率。
组件化的核心目标是 解耦 :将项目拆分为独立、可复用的组件,通过 “中间件” 实现组件间通信,解决上述问题。
二、iOS 组件化如何分层?
组件化架构通常分为 5 层(自底向上),每层职责清晰、依赖单向(上层依赖下层,禁止反向依赖):
三、CTMediator 的 OC 与 Swift 实践(组件间通信)
CTMediator 是基于 “Target-Action” 模式的组件化中间件,通过运行时(OC)或桥接(Swift)实现组件间 “无依赖调用”。其核心原理:调用方通过中间件(CTMediator)发送 “指令”,中间件找到目标组件的 “Target” 类,执行对应的 “Action” 方法。
3.1. OC 实践代码
假设场景:“订单组件” 调用 “支付组件” 的支付功能。
(1)中间件 CTMediator(基础类,全局唯一)
objective-c
// CTMediator.h#import @interface CTMediator : NSObject+ (instancetype)sharedInstance;// 支付组件调用方法(中间件声明)- (void)payWithOrderId:(NSString *)orderId callback:(void(^)(BOOL success))callback;@end// CTMediator.m#import \"CTMediator.h\"#import @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 @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.swiftimport 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 in callback(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 in print(\"支付结果:\\(success)\") } }}
四、组件化与工程化、插件化的区别和优势
组件化的独特优势:
- 相比工程化:工程化是 “流程规范”,组件化是 “架构设计”,前者为后者提供落地保障;
- 相比插件化:组件化是 “静态拆分”(编译期整合),兼容性更好(无动态加载风险),适合业务稳定的大型项目;插件化是 “动态加载”,适合需频繁更新的场景,但实现复杂且受 iOS 审核限制(动态库可能被拒)。
总结
组件化是大型 iOS 项目解决耦合、提升协作效率的核心方案,通过分层设计和 CTMediator 等中间件实现模块解耦;其与工程化(流程规范)、插件化(动态加载)定位不同,需根据项目规模和业务需求选择。