iOS应用架构设计:MVC、MVVM、VIPER对比(文科生也能看懂!)

极客生活家
2025-12-16 07:13
阅读 475

作者自述:我曾是一个历史系毕业生,自学转码3年,如今在一家中型互联网公司做iOS开发。当初面试时被问到“你项目用的是什么架构?”,我支支吾吾答不上来,差点错失offer。今天这篇教程,就是写给和曾经的我一样迷茫的零基础朋友——不用怕,架构没那么玄!


为什么你需要了解架构?

很多人一听到“架构”就头大,以为是高深莫测的东西。其实架构就是组织代码的方式,就像装修房子要先规划水电、隔断一样。

  • 没有架构 → 所有代码堆在一个文件里(俗称“意大利面条式代码”)
  • 有架构 → 职责分明,改bug不手抖,加功能不崩溃

而且!这是高频面试题!我面试过10+家公司,8家都问了类似问题:“你们项目用什么架构?为什么选它?”


环境准备:5分钟搭好开发环境

💡 小贴士:你不需要买Mac!可以用MacInCloud远程租用(适合初期学习)。

  1. 安装 Xcode(App Store 免费下载)
  2. 打开 Xcode → Create a new Xcode project
  3. 选择 App → 语言选 Swift,界面选 Storyboard
  4. 给项目起个名字,比如 ArchitectureDemo

✅ 至此,你的开发环境就 ready 了!


核心概念:三大架构到底是什么?

我们用一个生活场景来类比:

你要做一顿饭

  • MVC:你(Controller)既要切菜(Model),又要炒菜(View)——累死!
  • MVVM:你(ViewModel)只管下指令,有个机器人(View)帮你炒菜,食材管家(Model)备好料
  • VIPER:你请了一个团队:采购员(Interactor)、厨师长(Presenter)、服务员(View)、调度员(Router)、食材库(Entity)

下面逐个拆解。


1. MVC(Model-View-Controller)

苹果官方推荐架构,也是Xcode模板默认结构。

三部分职责:

  • Model:数据(比如用户信息、网络请求结果)
  • View:界面(按钮、标签、图片)
  • Controller:协调 Model 和 View(比如点击按钮后更新数据并刷新界面)

⚠️ 我踩过的坑:

我早期把所有逻辑都塞进 ViewController,导致一个文件3000行!后来才知道这叫 Massive View Controller(巨无霸控制器)——这是MVC最常见的反模式!

示例:显示用户名

// Model
struct User {
    let name: String
}

// ViewController (Controller)
class ProfileViewController: UIViewController {
    @IBOutlet weak var nameLabel: UILabel!
    
    var user = User(name: "小明")
    
    override func viewDidLoad() {
        super.viewDidLoad()
        nameLabel.text = user.name  // Controller 直接操作 View 和 Model
    }
}

✅ 优点:简单,上手快
❌ 缺点:Controller 容易膨胀,测试困难


2. MVVM(Model-View-ViewModel)

前端开发者最爱!尤其从 React/Vue 转过来的同学会感到亲切。

核心思想:View 和 Model 解耦,通过 ViewModel 中转。

关键变化:

  • ViewModel:持有 Model 数据,并暴露给 View 的“可绑定属性”
  • 双向绑定(iOS常用 KVO 或 Combine 实现):View 变化自动同步到 ViewModel

示例:用 MVVM 显示用户名

// ViewModel
class ProfileViewModel {
    let userName: String
    
    init(user: User) {
        self.userName = user.name
    }
}

// ViewController
class ProfileViewController: UIViewController {
    @IBOutlet weak var nameLabel: UILabel!
    
    var viewModel: ProfileViewModel!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        nameLabel.text = viewModel.userName  // 只依赖 ViewModel,不碰 Model
    }
}

✅ 优点:View 更“傻”,逻辑集中在 ViewModel,易测试
❌ 缺点:需要学习绑定机制(如 Combine、RxSwift)


3. VIPER(View-Interactor-Presenter-Entity-Router)

企业级架构,适合大型项目,但学习成本高。

五个角色各司其职:

角色 职责
View 只负责显示和用户交互(比如按钮点击)
Presenter 接收 View 事件,向 Interactor 要数据
Interactor 处理业务逻辑(如网络请求、数据库)
Entity 纯数据模型(类似 Model)
Router 页面跳转逻辑

示例:VIPER 结构(简化版)

// Entity
struct User { let name: String }

// Interactor
class ProfileInteractor {
    func fetchUser() -> User {
        return User(name: "小明")
    }
}

// Presenter
class ProfilePresenter {
    weak var view: ProfileView?
    let interactor = ProfileInteractor()
    
    func viewDidLoad() {
        let user = interactor.fetchUser()
        view?.showUserName(user.name)
    }
}

// View (通常是 ViewController)
class ProfileViewController: UIViewController, ProfileView {
    @IBOutlet weak var nameLabel: UILabel!
    
    var presenter: ProfilePresenter!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        presenter.viewDidLoad()
    }
    
    func showUserName(_ name: String) {
        nameLabel.text = name
    }
}

✅ 优点:职责极度清晰,适合团队协作
❌ 缺点:文件多,样板代码多,小项目杀鸡用牛刀


架构对比表:一目了然

特性 MVC MVVM VIPER
学习难度 ⭐⭐ ⭐⭐⭐⭐
适合项目规模 小型 中小型 大型
测试友好度 极高
文件数量 中等
前端友好度 一般 高(类似 React)
面试题出现频率

实战:用三种架构写同一个功能

功能:点击按钮,显示“Hello, iOS!”

1. MVC 版本

class HelloViewController: UIViewController {
    @IBOutlet weak var label: UILabel!
    @IBAction func buttonTapped(_ sender: UIButton) {
        label.text = "Hello, iOS!"
    }
}

2. MVVM 版本

class HelloViewModel {
    let message = "Hello, iOS!"
}

class HelloViewController: UIViewController {
    @IBOutlet weak var label: UILabel!
    let viewModel = HelloViewModel()
    
    @IBAction func buttonTapped(_ sender: UIButton) {
        label.text = viewModel.message
    }
}

3. VIPER 版本(简化)

protocol HelloView: AnyObject {
    func displayMessage(_ msg: String)
}

class HelloPresenter {
    weak var view: HelloView?
    func handleButtonTap() {
        view?.displayMessage("Hello, iOS!")
    }
}

class HelloViewController: UIViewController, HelloView {
    @IBOutlet weak var label: UILabel!
    let presenter = HelloPresenter()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        presenter.view = self
    }
    
    @IBAction func buttonTapped(_ sender: UIButton) {
        presenter.handleButtonTap()
    }
    
    func displayMessage(_ msg: String) {
        label.text = msg
    }
}

新手常见问题 & 解答

Q1:我该从哪个架构开始学?

:先掌握 MVC(苹果默认),再学 MVVM(行业主流)。VIPER 等找工作或做大项目再深入。

Q2:MVVM 必须用 RxSwift 吗?

:不必!初学者可用简单的属性传递(如上面示例)。RxSwift/Combine 是进阶工具,不是 MVVM 的必要条件。

Q3:面试被问“为什么不用 VIPER”怎么答?

:诚实回答!比如:“我们项目规模小,VIPER 会增加不必要的复杂度。但我们评估过,未来模块膨胀时会考虑迁移。”


学习建议:下一步怎么走?

  1. 动手实践:用三种架构各写一个小 App(比如 Todo List)
  2. 读经典书籍
    • 《iOS Programming: The Big Nerd Ranch Guide》(MVC 基础)
    • 《Design Patterns in Swift》(含 MVVM 实现)
    • 《Clean Architecture》(理解架构本质)
  3. 关注前端思想:MVVM 在前端很成熟,看看 Vue/React 的状态管理,能反哺 iOS 理解
  4. 模拟面试题挑战
    • “MVC 的缺点是什么?”
    • “MVVM 如何解决 ViewController 膨胀?”
    • “VIPER 各模块如何通信?”

最后的话

我当初学架构时,觉得它们像天书。但当你亲手写过、踩过坑、重构过代码,就会发现:架构不是枷锁,而是让代码活得更久的氧气

别怕犯错,我的第一个 MVVM 项目绑定了10层嵌套,跑起来卡成PPT……但正是这些坑,让我在面试时能自信地说:“我试过,我知道为什么选这个。”

祝你编码愉快,早日拿到心仪 offer! 🚀

作者注:本文所有代码均可在 Xcode 14+ 运行。如有疑问,欢迎留言讨论。

评论 0

最热最新
暂无评论
匿名用户Lv.1
0
影响力
0
文章
0
粉丝