SwiftUI 中的模块化特性架构
Source: Dev.to
🧩 1. 什么是功能模块?
功能模块是一个 自包含的单元,代表应用中的一个功能块:
Home/
Profile/
Settings/
Feed/
Auth/
OfflineSync/
Notifications/
每个模块包含:
- 视图(Views)
- 视图模型(ViewModels)
- 数据模型(Models)
- 服务(Services)
- 路由定义(Routing definitions)
- 预览(Previews)
- Mock 数据(Mocks)
一个功能应该可以被移除而不破坏整个应用。如果你可以删除一个文件夹且其他地方都不受影响 → 那么它是模块化的。
📁 2. 推荐的文件夹结构
下面是一种干净、可扩展的模式:
AppName/
│
├── App/
│ ├── AppState.swift
│ ├── AppEntry.swift
│ └── RootView.swift
│
├── Modules/
│ ├── Home/
│ │ ├── HomeView.swift
│ │ ├── HomeViewModel.swift
│ │ ├── HomeService.swift
│ │ ├── HomeRoute.swift
│ │ └── HomeMocks.swift
│ │
│ ├── Profile/
│ │ ├── ProfileView.swift
│ │ ├── ProfileViewModel.swift
│ │ ├── ProfileService.swift
│ │ ├── ProfileRoute.swift
│ │ └── ProfileMocks.swift
│ │
│ ├── Settings/
│ │ ├── SettingsView.swift
│ │ ├── SettingsViewModel.swift
│ │ └── SettingsMocks.swift
│ │
│ └── Shared/
│ ├── Components/
│ ├── Models/
│ ├── Utilities/
│ └── Styles/
│
├── Services/
│
└── Resources/
不再有“上帝文件夹”——每个模块都是独立的世界。
🔌 3. 模块边界的依赖注入
每个模块通过协议声明 它需要什么:
protocol ProfileServiceProtocol {
func fetchProfile(id: String) async throws -> Profile
}
模块 不 知道具体实现(真实 API 客户端、离线缓存、Mock 数据源、测试环境)。应用在外部注入具体的服务:
ProfileViewModel(
service: appServices.profileService
)
好处
- 可测试性
- 灵活性
- 易于替换
- 隔离性
🧭 4. 模块间的路由
每个模块定义自己的路由类型:
enum ProfileRoute: Hashable {
case details(id: String)
case followers(id: String)
}
根视图聚合各模块的路由:
enum AppRoute: Hashable {
case profile(ProfileRoute)
case home
case settings
}
统一的导航处理:
.navigationDestination(for: AppRoute.self) { route in
switch route {
case .profile(let pr): ProfileRouter.view(for: pr)
case .home: HomeView()
case .settings: SettingsView()
}
}
模块专属的路由器:
struct ProfileRouter {
@ViewBuilder static func view(for route: ProfileRoute) -> some View {
switch route {
case .details(let id):
ProfileView(userID: id)
case .followers(let id):
FollowersView(userID: id)
}
}
}
模块保持独立。
🧪 5. 功能模块应完全可预览
示例预览:
#Preview("Profile Details") {
ProfileView(
viewModel: ProfileViewModel(
service: MockProfileService()
)
)
}
自包含的预览
- 加速开发
- 防止回归
- 降低认知负担
预览文件夹成为每个模块的迷你设计系统。
🏎 6. 模块化带来的性能提升
模块化代码库带来:
- 更快的构建时间 – 只重新编译变动的模块。
- 更安全的重构 – 模块之间不泄露内部细节。
- 更好的测试隔离 – 按模块运行测试。
- 更小的认知负荷 – 新成员能快速理解功能。
- 更佳的 CI 并行化 – 每个模块可以是独立的测试目标。
这些收益在拥有 10+ 屏幕的应用中尤为明显。
🔄 7. 功能通信模式
模块 不应 直接相互 import。可以使用以下模式之一:
- AppRoute(最常用) – 根层协调导航。
- 服务层 – 模块通过共享的服务协议进行通信。
- 事件总线 – 处理全局副作用,如埋点统计。
- 共享模型 – 明确放在
Modules/Shared下。
关键规则: 📌 模块向“上层”说话,而不是横向交流。
🧵 8. 在每个模块内部隔离业务逻辑
所有业务逻辑都应位于对应模块内部:
Profile/
ProfileViewModel.swift
ProfileService.swift
ProfileValidation.swift
ProfileFormatter.swift
避免:
- 全局工具类
- 共享状态
- 引入无关模块
这样可以保持代码所有权的清晰。
🧱 9. 跨应用公共模块
你的 Modules/Shared 文件夹应包含:
- 基础组件
- 排版(Typography)
- 主题系统
- 全局模型
- 网络工具
- 动画帮助类
绝不要在这里放置特定功能的逻辑。
🧭 10. 何时该进行模块化?
使用以下检查清单:
- 应用拥有 6+ 个屏幕
- 两位或以上开发者 在同一代码库工作
- 功能可以 独立发布
- 需要 快速预览
- 需要 安全的重构
- 使用 深度链接
- 支持 离线模式
- 使用 DI + 全局 AppState
如果满足 3 条或以上 → 进行模块化。
🚀 最后思考
对 SwiftUI 应用进行模块化会彻底改变你的代码库:
- 更易于开发
- 更易于测试
- 更易于扩展
- 更易于重构
- 更易于协作
这是一项能显著提升架构质量的重大升级。