iOS应用架构设计:MVC、MVVM、VIPER对比(零基础入门教程)
大家好,我是阿杰,一名在大厂干了3年iOS开发的工程师,平时也在B站做技术UP主,经常收到粉丝私信问我:“iOS架构到底该怎么学?”、“面试官总问MVC和MVVM的区别,我该怎么回答?”
我当初学的时候,也是一头雾水。看到“VIPER”、“Clean Architecture”这些词就发怵,以为是什么高深莫测的东西。其实,它们只是组织代码的方式不同而已,就像你整理书桌:有人按科目分,有人按颜色分,有人用抽屉分区——目的都是让东西更好找、更好用。
今天这篇教程,就是为完全零基础的同学准备的。我会用最通俗的语言,配合真实可运行的代码示例,带你一步步理解三种主流iOS架构:MVC、MVVM、VIPER。文章还会结合面试题场景,并简单聊聊它们和后端协作的关系。学完这篇,你不仅能写出更清晰的代码,还能在面试中自信作答!
一、为什么需要架构?不写架构不行吗?
先别急着敲代码!我们先搞清楚为什么要用架构。
想象一下:你写了一个简单的天气App,只有一屏,显示温度。这时候,你把所有代码(网络请求、UI更新、数据处理)都塞进一个ViewController里,没问题,跑得飞快。
但随着功能增加——要支持城市切换、历史记录、夜间模式……你的ViewController可能膨胀到2000行!改一处,崩三处;想加个新功能,根本找不到入口。
架构的作用,就是帮你把代码“分门别类”,让每一部分只做自己该做的事。
💡 新手常见误区:
“我项目小,不需要架构。”
错!哪怕只有1个页面,也建议用基础架构。养成好习惯,以后做大项目才不会手忙脚乱。
二、环境准备:你需要什么?
要跟着本教程动手实践,请确保:
- 安装 Xcode 14 或更高版本(免费,Mac App Store下载)
- 会创建一个 Single View App 项目
- 基础Swift语法(变量、函数、类)已了解
⚠️ 注意:本文使用 Swift 编写,不涉及Objective-C。
三、核心概念:三种架构到底是什么?
我们用一个模拟登录功能作为例子贯穿全文:用户输入账号密码,点击登录,调用接口,成功则跳转主页。
1. MVC(Model-View-Controller)
这是苹果官方推荐的默认架构,也是你新建项目时的默认结构。
- Model:数据模型,比如
User结构体 - View:UI界面,比如
UITextField,UIButton - Controller:
ViewController,负责协调 View 和 Model
✅ 优点:
- 简单直观,适合小型项目
- 苹果原生支持,文档多
❌ 缺点:
- Controller 容易变成“大胖子”(Massive ViewController)
- 逻辑耦合严重,难以测试
📝 代码示例(MVC)
// Model
struct User {
let username: String
let token: String
}
// Controller
class LoginViewController: UIViewController {
@IBOutlet weak var usernameField: UITextField!
@IBOutlet weak var passwordField: UITextField!
// 所有逻辑都在这里!
@IBAction func loginTapped() {
guard let username = usernameField.text,
let password = passwordField.text else { return }
// 模拟网络请求(实际应封装)
NetworkService.shared.login(username: username, password: password) { [weak self] result in
DispatchQueue.main.async {
switch result {
case .success(let user):
// 跳转主页
self?.navigateToHome(user: user)
case .failure(let error):
self?.showError(error)
}
}
}
}
private func navigateToHome(user: User) { /* ... */ }
private func showError(_ error: Error) { /* ... */ }
}
🔍 面试题常考:
“MVC的缺点是什么?”
标准答案:Controller承担了太多职责,导致代码难以维护和测试。
2. MVVM(Model-View-ViewModel)
为了解决MVC的“胖Controller”问题,MVVM把业务逻辑从Controller中抽出来,放到 ViewModel 中。
- View:
ViewController+ UI组件(只负责展示和用户交互) - ViewModel:处理数据转换、网络请求、业务逻辑
- Model:同MVC
✅ 优点:
- Controller 变轻了
- ViewModel 易于单元测试
- 支持数据绑定(配合 Combine 或 RxSwift 更强)
❌ 缺点:
- 学习成本略高
- 小项目可能“杀鸡用牛刀”
📝 代码示例(MVVM)
// ViewModel
class LoginViewModel {
var onLoginSuccess: ((User) -> Void)?
var onLoginFailure: ((Error) -> Void)?
func login(username: String, password: String) {
NetworkService.shared.login(username: username, password: password) { [weak self] result in
switch result {
case .success(let user):
self?.onLoginSuccess?(user)
case .failure(let error):
self?.onLoginFailure?(error)
}
}
}
}
// Controller
class LoginViewController: UIViewController {
@IBOutlet weak var usernameField: UITextField!
@IBOutlet weak var passwordField: UITextField!
private let viewModel = LoginViewModel()
override func viewDidLoad() {
super.viewDidLoad()
setupBindings()
}
private func setupBindings() {
viewModel.onLoginSuccess = { [weak self] user in
self?.navigateToHome(user: user)
}
viewModel.onLoginFailure = { [weak self] error in
self?.showError(error)
}
}
@IBAction func loginTapped() {
guard let username = usernameField.text,
let password = passwordField.text else { return }
viewModel.login(username: username, password: password)
}
}
💡 亲身体验:
我第一家公司用的就是MVVM,配合RxSwift做数据绑定,Controller真的清爽很多!
3. VIPER(View-Interactor-Presenter-Entity-Router)
这是最复杂但最解耦的架构,适合大型团队协作项目。
- View:只负责UI展示,把用户操作转发给Presenter
- Presenter:接收View事件,调用Interactor,格式化数据给View
- Interactor:包含业务逻辑(相当于MVVM的ViewModel)
- Entity:数据模型(相当于Model)
- Router:负责页面跳转(解耦导航逻辑)
✅ 优点:
- 高度解耦,模块职责清晰
- 极易测试(每个组件都可独立Mock)
- 团队协作时冲突少
❌ 缺点:
- 文件数量爆炸(一个小功能5个文件)
- 上手门槛高,小项目不划算
📝 代码示例(VIPER - 精简版)
// Entity
struct User { let username: String; let token: String }
// Interactor
protocol LoginInteractorInput {
func login(username: String, password: String)
}
class LoginInteractor: LoginInteractorInput {
weak var output: LoginInteractorOutput?
func login(username: String, password: String) {
NetworkService.shared.login(username: username, password: password) { result in
switch result {
case .success(let user):
self.output?.didLoginSuccessfully(user: user)
case .failure(let error):
self.output?.didFailLogin(error: error)
}
}
}
}
protocol LoginInteractorOutput: AnyObject {
func didLoginSuccessfully(user: User)
func didFailLogin(error: Error)
}
// Presenter
protocol LoginPresenterInput {
func viewDidLoad()
func loginButtonTapped(username: String, password: String)
}
class LoginPresenter: LoginPresenterInput {
weak var view: LoginViewInput?
var interactor: LoginInteractorInput
var router: LoginRouterInput
init(interactor: LoginInteractorInput, router: LoginRouterInput) {
self.interactor = interactor
self.router = router
}
func loginButtonTapped(username: String, password: String) {
interactor.login(username: username, password: password)
}
}
extension LoginPresenter: LoginInteractorOutput {
func didLoginSuccessfully(user: User) {
router.navigateToHome(user: user)
}
func didFailLogin(error: Error) {
view?.showError(error)
}
}
// View (ViewController)
protocol LoginViewInput: AnyObject {
func showError(_ error: Error)
}
class LoginViewController: UIViewController, LoginViewInput {
@IBOutlet weak var usernameField: UITextField!
@IBOutlet weak var passwordField: UITextField!
var presenter: LoginPresenterInput!
@IBAction func loginTapped() {
guard let username = usernameField.text,
let password = passwordField.text else { return }
presenter.loginButtonTapped(username: username, password: password)
}
func showError(_ error: Error) { /* 显示错误 */ }
}
🤯 别慌!看起来文件多,但每个文件都很小,职责单一。
我当初第一次看VIPER代码,也觉得“这也太啰嗦了吧!”
但后来参与一个50人团队的金融App,才发现这种严格分工能避免无数bug。
四、实战对比:一张表说清楚区别
| 维度 | MVC | MVVM | VIPER |
|---|---|---|---|
| 文件数量 | 少(1个VC) | 中(VC + VM) | 多(5+文件) |
| Controller负担 | 重 | 轻 | 极轻 |
| 可测试性 | 差 | 好 | 极好 |
| 学习成本 | 低 | 中 | 高 |
| 适合场景 | 小型Demo、快速原型 | 中大型App、注重测试 | 大型团队、长期维护项目 |
| 与后端协作 | 直接在VC调API | 在VM封装API | 在Interactor调用Service层 |
💬 关于“后端”的说明:
无论哪种架构,网络请求都应该封装成独立的Service层(如NetworkService),而不是直接写在VC/VM/Interactor里。这样后端接口变更时,只需改Service,不影响上层逻辑。
五、新手常见问题解答
Q1:我该选哪种架构?
- 刚入门 → 从 MVC 开始,理解基本分层
- 想进阶/找工作 → 必学 MVVM
- 面大厂/做复杂App → 了解 VIPER 思想(不一定要全用)
Q2:MVVM一定要用RxSwift或Combine吗?
不用!数据绑定是加分项,不是必需品。你可以像我上面那样,用闭包回调实现。
Q3:VIPER是不是过度设计?
对小项目是的。但如果你的App要维护3年以上,VIPER的前期投入是值得的。
Q4:面试被问“你怎么选架构”怎么答?
标准话术:
“根据项目规模和团队情况选择。小项目用MVC快速迭代;中大型项目用MVVM保证可维护性和可测试性;超大型项目或金融类App考虑VIPER确保高度解耦。”
六、学习建议 & 避坑指南
✅ 正确学习路径:
- 先用MVC写2-3个小Demo(如TodoList、天气App)
- 把其中一个Demo改成MVVM,体会差异
- 阅读开源项目(如GitHub上的MVVM示例)
- 尝试用VIPER写一个登录模块(不必全功能)
⚠️ 避坑提醒:
- 不要为了架构而架构:先跑通功能,再考虑重构
- 网络层必须独立:无论哪种架构,都要封装
APIService - 别死记硬背:理解“为什么需要解耦”比记住定义更重要
📚 下一步学什么?
- 深入学习 Combine 或 RxSwift(用于MVVM数据绑定)
- 了解 Coordinator 模式(解决VIPER的Router复杂度)
- 研究 Clean Architecture(VIPER的升级版)
结语
架构不是银弹,没有“最好”,只有“最合适”。我当初学的时候,也是从一行行MVC代码开始,慢慢体会到解耦的价值。
希望这篇教程能帮你迈出第一步。如果你觉得有用,欢迎去B站搜“阿杰iOS”,我会持续更新更多零基础友好的实战教程!
最后送大家一句话:好的架构,是让你半年后回看代码时,还能看懂自己写的啥。
Happy Coding!🚀

评论 0