游乐游手机版
首页/AI教程/文章详情

Swift MVVM架构完整列表数据展示与交互实战

时间:2026-05-31 07:50
基于MVVM架构,使用原生Swift实现列表数据展示与交互功能,涵盖数据渲染、单元格复用、点击回调及数据刷新。Model承载数据,ViewModel处理业务逻辑并通过闭包回调视图,View专注UI展示,实现代码分层解耦,支持iOS14+,不依赖第三方框架。

Swift 基于MVVM架构实现完整列表数据展示与交互功能实战案例

一、架构简介

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

Swift 基于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 展示。代码分层清晰,后期维护和扩展都省心。

如果后续项目需要扩展,可以在这个基础上继续加:下拉刷新、上拉加载更多、网络异常处理、空页面占位图等通用功能,适配更复杂的业务场景完全没问题。

来源:https://juejin.cn/post/7644853171174588422
上一篇标题长度限制30汉字60字符内仅一个标题 下一篇TweetyAI人工智能聊天机器人的功能特点及使用指南
本站内容用于信息整理与展示,如有侵权或内容问题请及时联系处理。

相关推荐

补充同频道和同主题内容,方便继续浏览更多相关内容。

同类最新

继续查看同栏目最近更新的文章。

更多
Codex手机端上线,免费用户也能使用
AI教程 · 2026-05-31

Codex手机端上线,免费用户也能使用

今天,OpenAI官方发了一条推文:Codex正式登陆ChatGPT手机端。 iOS和Android都能用,把ChatGPT App更新一下就能看到。而且好消息是,所有套餐都覆盖——Free和Go用户也没被落下。 先说说这玩意儿到底能干嘛。 过去用Codex有个挺烦人的场景:你在电脑上让它跑一个任务

AI漫剧风口崛起,重塑创作者收入结构
AI教程 · 2026-05-31

AI漫剧风口崛起,重塑创作者收入结构

同样是入局AI视频创作,赛道选没选对,结果天差地别。投入越多、内耗越大的创作者,往往是在方向上就出了问题。这一点,在《AI漫剧创作一本通》这本书里被讲得很透——它专门把AI广告片、AI宣传片和AI漫剧三大方向做了清晰的横向对比。广告片需求分散、复购率低;宣传片决策链条冗长、入行门槛偏高。二者都属于“

SQE岗位在企业质量管理中的关键作用
AI教程 · 2026-05-31

SQE岗位在企业质量管理中的关键作用

了解SQE岗位的职责与要求在当今职场中,SQE(供应商质量工程师)这个职位正日益受到青睐,吸引了众多求职者的关注。然而,很多人对于SQE究竟需要承担哪些工作、具备哪些硬核能力仍存在困惑。本文将从岗位职责、必备技能到面试准备,系统梳理SQE的核心要点,为您的职业发展提供清晰指引。1 SQE的主要职责

千面智娱AI动捕技术高效便捷助力动画创作
AI教程 · 2026-05-31

千面智娱AI动捕技术高效便捷助力动画创作

千面智娱产品介绍 回顾过去几年,3D动作捕捉技术主要局限于专业工作室与高端影视团队之中。然而,如今这一局面已被打破。千面智娱正是降低门槛的关键力量——作为一个专注于动画制作与AI动捕技术的平台,它强调高效与便捷,旨在让更多创作者能够轻松上手、顺畅使用。那么,它究竟具备哪些能力?适合哪些人群?接下来将

全面掌握Excel表格提升数据处理效率的实用技巧
AI教程 · 2026-05-31

全面掌握Excel表格提升数据处理效率的实用技巧

```html 在日常办公中,Excel几乎是每一位职场人士不可或缺的利器,而其中的elexe表格功能,许多用户尚未充分发掘其潜力。简单来说,elexe表格能够将普通数据区域转换为智能、结构化的表格,显著降低重复性操作。接下来,我们从创建到实际应用,分步骤进行详细说明。 方法一:创建elexe表格