在 iOS 开发中,架构设计一直是被广泛讨论的话题。很多团队在项目初期不重视架构,导致后期代码难以维护、新功能难以添加。本文分享我们在多个 iOS 项目中积累的架构经验。
为什么需要架构?
简单说,架构是为了解决三个问题:
- 代码组织:文件怎么放?类怎么划分?
- 职责分离:谁负责什么?数据怎么流动?
- 可测试性:怎么写单元测试?怎么 Mock?
好的架构不是炫技,而是让新加入的团队成员能快速上手。
常见架构模式对比
MVC - 经典但容易变成 Massive View Controller
iOS 开发者最熟悉的模式。但实际项目中,ViewController 往往会变得非常臃肿:
- 网络请求
- 数据处理
- UI 更新
- 业务逻辑
最后变成几千行的"上帝类"。
MVVM - 我们的首选
将业务逻辑从 ViewController 移到 ViewModel:
- Model:数据模型,纯数据,无 UI 逻辑
- View:UIView 及其子类,只负责显示和响应用户交互
- ViewModel:持有 Model,提供 View 需要的数据绑定接口
优点:ViewModel 可独立测试,View 变得轻量。
Clean Architecture - 复杂项目的选择
分层更细,适合大型项目:
- Presentation Layer:UI 和展示逻辑
- Domain Layer:核心业务逻辑,不依赖外部
- Data Layer:数据访问,网络、数据库
我们的实践建议
1. 小项目:MVVM 足够
不要过度设计。如果项目只有几个页面,MVVM 是最佳选择。
2. 用 Protocol 解耦
定义清晰的接口,避免类之间的强耦合:
protocol UserService {
func fetchUser(id: String) async throws -> User
}
class NetworkUserService: UserService {
// 网络实现
}
class MockUserService: UserService {
// 测试用 Mock
}
3. 数据流要单向
View → ViewModel → Model,避免循环依赖。我们用 Coordinator 模式管理页面跳转:
- 每个页面有一个 Coordinator
- Coordinator 负责创建下一个页面的 ViewModel 和 View
- ViewModel 通过回调通知 Coordinator 跳转
4. 依赖注入
通过构造函数或属性注入依赖,方便测试:
class UserViewModel {
private let userService: UserService
init(userService: UserService) {
self.userService = userService
}
}
常见陷阱
- 过度抽象:为了抽象而抽象,增加理解成本
- 忽略生命周期:ViewModel 持有 View 导致循环引用
- 数据冗余:Model 和 ViewModel 之间简单映射,没有实际价值
总结
架构没有银弹。我们的经验是:
- 从简单开始,演进式重构
- MVVM 适合大多数项目
- 用 Protocol 和依赖注入提高可测试性
- 关注代码可读性,而非炫技
好的架构是让团队开发更高效,而不是更复杂。