Swift 中的 MVVM 架构深度解析与最佳实践 一、Swift MVVM 核心架构 二、核心组件实现 1. Model 层设计 2. ViewModel 层实现 3. View 层实现 (SwiftUI) 三、数据绑定机制 1. SwiftUI 绑定方式 2. Combine 高级绑定 四、依赖注入方案 五、路由导航实现 六、测试策略 1. ViewModel 单元测试 2. UI 快照测试 七、性能优化技巧 八、常见问题解决方案 九、SwiftUI 最佳实践 十、架构演进建议 十一、性能监控工具 1. Instruments 关键指标 2. 自定义监控 十二、Swift 生态工具链 总结:Swift MVVM 最佳实践
一、Swift MVVM 核心架构
数据绑定
请求/响应
数据更新
状态更新
API/数据库
导航
View
ViewModel
Model
Service
Router
二、核心组件实现
1. Model 层设计
struct User : Codable { let id: Int var name: String var email: String func isValidEmail ( ) - > Bool { let regex = #"^\S+@\S+\.\S+$" #return email. range ( of: regex, options: . regularExpression) != nil }
}
2. ViewModel 层实现
final class UserViewModel : ObservableObject { @Published var user: User @Published var isLoading = false @Published var errorMessage: String ? private let apiService: APIServiceProtocol private let storage: UserStorageProtocol init ( user: User , apiService: APIServiceProtocol = APIService ( ) , storage: UserStorageProtocol = UserStorage ( ) ) { self . user = userself . apiService = apiServiceself . storage = storage} func saveUser ( ) { guard user. isValidEmail ( ) else { errorMessage = "Invalid email format" return } isLoading = true apiService. updateUser ( user) { [ weak self ] result in DispatchQueue . main. async { self ? . isLoading = false switch result { case . success ( let updatedUser) : self ? . user = updatedUserself ? . storage. saveUser ( updatedUser) case . failure ( let error) : self ? . errorMessage = error. localizedDescription} } } }
}
3. View 层实现 (SwiftUI)
struct UserView : View { @StateObject var viewModel: UserViewModel @EnvironmentObject var router: Router var body: some View { Form { Section ( header: Text ( "Personal Info" ) ) { TextField ( "Name" , text: $viewModel. user. name) TextField ( "Email" , text: $viewModel. user. email) . keyboardType ( . emailAddress) . autocapitalization ( . none ) } Button ( "Save" ) { viewModel. saveUser ( ) } . disabled ( viewModel. isLoading) if let error = viewModel. errorMessage { Text ( error) . foregroundColor ( . red) } } . navigationTitle ( "Profile" ) . overlay { if viewModel. isLoading { ProgressView ( ) } } }
}
三、数据绑定机制
1. SwiftUI 绑定方式
TextField ( "Name" , text: $viewModel. user. name)
. onReceive ( viewModel. $errorMessage) { error in if error != nil { showAlert = true }
}
Button ( "Save" , action: viewModel. saveUser)
2. Combine 高级绑定
class UserViewModel : ObservableObject { private var cancellables = Set < AnyCancellable > ( ) init ( ) { $user. debounce ( for : . seconds ( 0.5 ) , scheduler: RunLoop . main) . filter { $0 . name. count > 3 } . sink { [ weak self ] _ in self ? . autoSave ( ) } . store ( in : & cancellables) }
}
四、依赖注入方案
1. 构造函数注入
struct UserView_Previews : PreviewProvider { static var previews: some View { let mockUser = User ( id: 1 , name: "Test" , email: "test@example.com" ) let mockService = MockAPIService ( ) let viewModel = UserViewModel ( user: mockUser, apiService: mockService) UserView ( viewModel: viewModel) }
}
2. 依赖容器
class DIContainer { static let shared = DIContainer ( ) lazy var apiService: APIServiceProtocol = { return ProcessInfo . processInfo. isUITesting ? MockAPIService ( ) : APIService ( ) } ( ) lazy var storage: UserStorageProtocol = { return UserDefaultsStorage ( ) } ( )
}
let viewModel = UserViewModel ( user: user, apiService: DIContainer . shared. apiService, storage: DIContainer . shared. storage
)
五、路由导航实现
1. 路由协议
enum Route : Hashable { case userDetail ( User ) case settingscase logout
} class Router : ObservableObject { @Published var path = NavigationPath ( ) func navigate ( to route: Route ) { path. append ( route) } func popToRoot ( ) { path. removeLast ( path. count ) }
}
2. ViewModel 中的导航
class UserListViewModel : ObservableObject { @Published var users: [ User ] = [ ] private let router: Router init ( router: Router ) { self . router = router} func selectUser ( _ user: User ) { router. navigate ( to: . userDetail ( user) ) }
}
六、测试策略
1. ViewModel 单元测试
class UserViewModelTests : XCTestCase { var sut: UserViewModel ! var mockService: MockAPIService ! override func setUp ( ) { mockService = MockAPIService ( ) let user = User ( id: 1 , name: "John" , email: "test@test.com" ) sut = UserViewModel ( user: user, apiService: mockService) } func testValidEmailSavesSuccessfully ( ) { mockService. updateUserResult = . success ( User ( id: 1 , name: "John" , email: "valid@email.com" ) ) sut. user. email = "valid@email.com" sut. saveUser ( ) XCTAssertFalse ( sut. isLoading) XCTAssertNil ( sut. errorMessage) XCTAssertEqual ( sut. user. email, "valid@email.com" ) } func testInvalidEmailShowsError ( ) { sut. user. email = "invalid-email" sut. saveUser ( ) XCTAssertEqual ( sut. errorMessage, "Invalid email format" ) }
}
2. UI 快照测试
func testUserViewLoadingState ( ) { let viewModel = UserViewModel ( user: . mock) viewModel. isLoading = true let view = UserView ( viewModel: viewModel) assertSnapshot ( of: view, as : . image ( layout: . device ( config: . iPhone13) ) )
}
七、性能优化技巧
1. 高效数据绑定
class UserViewModel : ObservableObject { @Published private ( set ) var user: User @Published private ( set ) var isLoading = false private var temporaryData: String = ""
}
2. 资源管理
func loadData ( ) { Task { @MainActor in isLoading = true do { user = try await apiService. fetchUser ( ) } catch { errorMessage = error. localizedDescription} isLoading = false }
}
八、常见问题解决方案
1. 循环引用处理
func fetchData ( ) { apiService. getData { [ weak self ] result in guard let self = self else { return } }
}
func fetchData ( ) { apiService. getData { [ unowned self ] result in }
}
2. 复杂状态管理
enum UserState { case loadingcase loaded ( User ) case error ( Error ) case editing
} class UserViewModel : ObservableObject { @Published var state: UserState = . loadingfunc loadUser ( ) { state = . loadingapiService. fetchUser { result in switch result { case . success ( let user) : state = . loaded ( user) case . failure ( let error) : state = . error ( error) } } }
}
九、SwiftUI 最佳实践
1. 视图优化
struct UserView : View { @ObservedObject var viewModel: UserViewModel var body: some View { VStack { if case . loaded ( let user) = viewModel. state { UserProfileView ( user: user) } SaveButton ( viewModel: viewModel) } }
}
struct SaveButton : View { @ObservedObject var viewModel: UserViewModel var body: some View { Button ( "Save" ) { viewModel. saveUser ( ) } . disabled ( viewModel. isSaving) }
}
2. 预览优化
struct UserView_Previews : PreviewProvider { static var previews: some View { Group { UserView ( viewModel: . previewLoaded) UserView ( viewModel: . previewLoading) UserView ( viewModel: . previewError) } }
} extension UserViewModel { static var previewLoaded: UserViewModel { let vm = UserViewModel ( user: . mock) vm. state = . loaded ( . mock) return vm}
}
十、架构演进建议
1. 中型项目增强
View
ViewModel
UseCase
Repository
API
Database
2. 大型项目方案
App /
├── Feature /
│ ├── User /
│ │ ├── Presentation / # View + ViewModel
│ │ ├── Domain / # Model + UseCase
│ │ └── Data / # Repository + DTO
│ └── Settings /
├── Core /
│ ├── Networking /
│ ├── Storage /
│ └── DI /
└── Shared / ├── Utilities / └── DesignSystem /
十一、性能监控工具
1. Instruments 关键指标
指标 正常范围 警告阈值 优化方案 内存占用 <50MB >100MB 检查强引用循环 CPU使用率 <30% >70% 优化数据绑定 刷新频率 60fps <50fps 简化复杂视图 启动时间 <1s >2s 延迟加载VM
2. 自定义监控
class PerformanceMonitor { static func track< T> ( _ operation: String , _ block: ( ) throws - > T) rethrows - > T { let start = CFAbsoluteTimeGetCurrent ( ) defer { let diff = CFAbsoluteTimeGetCurrent ( ) - startprint ( "⏱ $operation) took $diff)s" ) if diff > 0.1 { } } return try block ( ) }
}
func loadData ( ) { PerformanceMonitor . track ( "UserFetch" ) { viewModel. loadUser ( ) }
}
十二、Swift 生态工具链
1. 推荐库
库名 用途 集成方式 Combine 响应式编程 原生支持 Factory 依赖注入 SPM Quick/Nimble 单元测试 SPM ViewInspector SwiftUI 测试 SPM
2. 模板生成
brew install mint
mint install swiftmvvm/template
swiftmvvm generate UserFeature
总结:Swift MVVM 最佳实践
严格分层: View:只处理UI展示 ViewModel:处理视图逻辑 Model:封装业务逻辑 单向数据流:
测试策略: ViewModel:100%单元测试 View:快照测试 Model:业务逻辑测试 性能优化: 使用@Published精确控制 避免在View中处理业务逻辑 使用Task管理异步 架构演进: 小型项目:基础MVVM 中型项目:MVVM+UseCase 大型项目:模块化MVVM
黄金法则:保持View的"笨拙",让ViewModel成为唯一的真相源,让Model保持纯净的业务逻辑封装。