Swift MVVM架构完整列表数据展示与交互实战
Swift 基于MVVM架构实现完整列表数据展示与交互功能实战案例
一、架构简介
MVVM 在 iOS 开发圈子里已经算是主流标配了。跟传统的 MVC 相比,它把职责拆得更清楚:View 只管页面长什么样、用户怎么点;ViewModel 负责业务逻辑、数据处理和视图状态的管理;Model 就老老实实承载数据模型。这么一拆,视图和业务逻辑就彻底解耦了,代码可读性、可维护性,甚至单元测试的友好度,都上了一个台阶。对于列表类这种常规业务来说,MVVM 几乎是天然适配的。

这篇就以一个基础列表页为例,从零开始,把数据渲染、单元格复用、点击交互、数据刷新这些核心功能一一走通。全程用原生 Swift,适配 iOS 14+,不依赖第三方框架。
二、项目结构
目录划分清晰,严格遵循 MVVM 的分层逻辑:
├── Model // 数据模型层
├── ViewModel // 业务逻辑层
├── View // 视图层(控制器、自定义Cell)
三、代码实现
3.1 数据模型(Model)
先建一个列表数据源模型。采用 Codable 协议,方便后续网络数据解析。这里定义列表展示所需的几个核心字段:
import Foundation
// 列表数据模型
struct ListModel: Codable {
let id: Int
let title: String
let desc: String
}
3.2 视图模型(ViewModel)
ViewModel 是整个架构的枢纽层。它封装了数据请求、数据数组管理、单元格数据赋值、点击事件回调——但绝不持有任何视图对象。通过闭包来回调数据刷新和点击事件,视图和逻辑之间就彻底松绑了。
import Foundation
class ListViewModel {
// 数据源数组
private(set) var dataArray: [ListModel] = []
// 数据刷新回调
var reloadDataClosure: (() -> Void)?
// 单元格点击回调
var cellClickClosure: ((ListModel) -> Void)?
// 模拟请求本地/网络数据
func requestListData() {
// 模拟异步网络请求
DispatchQueue.global().asyncAfter(deadline: .now() + 0.5) { [weak self] in
guard let self = self else { return }
// 构造测试数据
let tempData = [
ListModel(id: 1, title: "Swift基础语法", desc: "Swift数据类型、函数与流程控制讲解"),
ListModel(id: 2, title: "UIKit控件使用", desc: "UILabel、UIButton、UITableView实战"),
ListModel(id: 3, title: "MVVM架构思想", desc: "架构分层与解耦设计原则")
]
self.dataArray = tempData
// 主线程回调刷新视图
DispatchQueue.main.async {
self.reloadDataClosure?()
}
}
}
// 获取单个单元格数据
func getCellModel(index: Int) -> ListModel? {
guard index >= 0, index < dataArray.count else { return nil }
return dataArray[index]
}
// 触发单元格点击事件
func didSelectRow(index: Int) {
guard let model = getCellModel(index: index) else { return }
cellClickClosure?(model)
}
}
3.3 自定义单元格(View)
ListCell 封装了 UITableViewCell,只负责两件事:UI 布局和数据赋值。不处理任何业务逻辑,ViewModel 把数据传过来,它照单显示就行。
import UIKit
class ListCell: UITableViewCell {
// UI控件
private let titleLabel: UILabel = {
let label = UILabel()
label.font = UIFont.systemFont(ofSize: 16, weight: .semibold)
return label
}()
private let descLabel: UILabel = {
let label = UILabel()
label.font = UIFont.systemFont(ofSize: 13)
label.textColor = .gray
label.numberOfLines = 0
return label
}()
// 初始化布局
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
setupUI()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
// 页面布局
private func setupUI() {
contentView.addSubview(titleLabel)
contentView.addSubview(descLabel)
titleLabel.translatesAutoresizingMaskIntoConstraints = false
descLabel.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
titleLabel.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 12),
titleLabel.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 16),
titleLabel.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -16),
descLabel.topAnchor.constraint(equalTo: titleLabel.bottomAnchor, constant: 8),
descLabel.leadingAnchor.constraint(equalTo: titleLabel.leadingAnchor),
descLabel.trailingAnchor.constraint(equalTo: titleLabel.trailingAnchor),
descLabel.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -12)
])
}
// 绑定数据
func configData(model: ListModel) {
titleLabel.text = model.title
descLabel.text = model.desc
}
}
3.4 主控制器(View)
控制器作为视图载体,职责很简单:创建视图、绑定 ViewModel 的回调、响应页面交互。所有业务逻辑都扔给 ViewModel 去处理,控制器只管“接活儿”。
import UIKit
class ListViewController: UIViewController {
// 初始化ViewModel
private let viewModel = ListViewModel()
private let tableView = UITableView()
private let cellID = "ListCell"
override func viewDidLoad() {
super.viewDidLoad()
setupBase()
setupTableView()
bindViewModel()
// 发起数据请求
viewModel.requestListData()
}
private func setupBase() {
view.backgroundColor = .white
title = "MVVM列表实战"
}
// 初始化表格
private func setupTableView() {
view.addSubview(tableView)
tableView.translatesAutoresizingMaskIntoConstraints = false
tableView.frame = view.bounds
tableView.delegate = self
tableView.dataSource = self
tableView.register(ListCell.self, forCellReuseIdentifier: cellID)
tableView.tableFooterView = UIView()
}
// 绑定ViewModel回调
private func bindViewModel() {
// 数据刷新
viewModel.reloadDataClosure = { [weak self] in
self?.tableView.reloadData()
}
// 单元格点击
viewModel.cellClickClosure = { model in
print("点击条目:(model.title),ID:(model.id)")
let alert = UIAlertController(title: "点击提示", message: model.title, preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "确定", style: .default))
self.present(alert, animated: true)
}
}
}
// UITableView 袋里与数据源
extension ListViewController: UITableViewDataSource, UITableViewDelegate {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return viewModel.dataArray.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: cellID, for: indexPath) as? ListCell,
let model = viewModel.getCellModel(index: indexPath.row) else {
return UITableViewCell()
}
cell.configData(model: model)
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
viewModel.didSelectRow(index: indexPath.row)
}
}
四、功能测试与总结
运行效果很直观:项目启动后,页面异步加载模拟数据,列表自动渲染;点击任意单元格,弹出提示弹窗并打印日志,单元格正常取消选中状态。整个交互流程一气呵成。
架构上的优势也一目了然:Model 只管数据,不带任何视图代码;ViewModel 独立处理数据请求和业务逻辑,可以单独做单元测试;View 只专注 UI 展示。代码分层清晰,后期维护和扩展都省心。
如果后续项目需要扩展,可以在这个基础上继续加:下拉刷新、上拉加载更多、网络异常处理、空页面占位图等通用功能,适配更复杂的业务场景完全没问题。
游乐网为非赢利性网站,所展示的游戏/软件/文章内容均来自于互联网或第三方用户上传分享,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系youleyoucom@outlook.com。
同类文章
Codex手机端上线,免费用户也能使用
今天,OpenAI官方发了一条推文:Codex正式登陆ChatGPT手机端。 iOS和Android都能用,把ChatGPT App更新一下就能看到。而且好消息是,所有套餐都覆盖——Free和Go用户也没被落下。 先说说这玩意儿到底能干嘛。 过去用Codex有个挺烦人的场景:你在电脑上让它跑一个任务
AI漫剧风口崛起,重塑创作者收入结构
同样是入局AI视频创作,赛道选没选对,结果天差地别。投入越多、内耗越大的创作者,往往是在方向上就出了问题。这一点,在《AI漫剧创作一本通》这本书里被讲得很透——它专门把AI广告片、AI宣传片和AI漫剧三大方向做了清晰的横向对比。广告片需求分散、复购率低;宣传片决策链条冗长、入行门槛偏高。二者都属于“
SQE岗位在企业质量管理中的关键作用
了解SQE岗位的职责与要求在当今职场中,SQE(供应商质量工程师)这个职位正日益受到青睐,吸引了众多求职者的关注。然而,很多人对于SQE究竟需要承担哪些工作、具备哪些硬核能力仍存在困惑。本文将从岗位职责、必备技能到面试准备,系统梳理SQE的核心要点,为您的职业发展提供清晰指引。1 SQE的主要职责
千面智娱AI动捕技术高效便捷助力动画创作
千面智娱产品介绍 回顾过去几年,3D动作捕捉技术主要局限于专业工作室与高端影视团队之中。然而,如今这一局面已被打破。千面智娱正是降低门槛的关键力量——作为一个专注于动画制作与AI动捕技术的平台,它强调高效与便捷,旨在让更多创作者能够轻松上手、顺畅使用。那么,它究竟具备哪些能力?适合哪些人群?接下来将
全面掌握Excel表格提升数据处理效率的实用技巧
```html 在日常办公中,Excel几乎是每一位职场人士不可或缺的利器,而其中的elexe表格功能,许多用户尚未充分发掘其潜力。简单来说,elexe表格能够将普通数据区域转换为智能、结构化的表格,显著降低重复性操作。接下来,我们从创建到实际应用,分步骤进行详细说明。 方法一:创建elexe表格
- 日榜
- 周榜
- 月榜
1
2
3
4
5
6
7
8
9
10
相关攻略
2015-03-10 11:25
2015-03-10 11:05
2021-08-04 13:30
2015-03-10 11:22
2015-03-10 12:39
2022-05-16 18:57
2025-05-23 13:43
2025-05-23 14:01
热门教程
- 游戏攻略
- 安卓教程
- 苹果教程
- 电脑教程
热门话题

