- 两列视频卡片流,支持上下滑动与点击到全屏播放页。
- 异步图片加载、网络数据获取与本地缓存;采用工厂模式与单例模式组织核心逻辑。
- 播放页沉浸式 UI,支持点击暂停/恢复、静音切换、点赞、进度条拖动与时间显示。
- UI 层:
ByteTest/UI/ContentView.swift列表与导航VideoCardView.swift卡片组件VideoPlayerView.swift全屏播放页面
- Core 层:
ByteTest/Core/VideoItem.swift数据模型:包含VideoItem字段id、coverUrl、tag、title、avatarUrl、nickname、playUrl、viewsCountVideoListViewModel.swift视图模型VideoRepository.swift仓库(网络 + 缓存)NetworkClient.swift网络单例DataStorage.swift存储单例VideoFactory.swift工厂(远端结构到模型)ServiceFactory.swift服务工厂(组装仓库与 VM)AppConstants.swift常量(播放地址与 Feed URL)
- 程序入口:
ByteTest/ByteTestApp.swift
- 触发加载:
ContentView出现时调用viewModel.load()(`ByteTest/UI/ContentView.swift) - 视图模型:
VideoListViewModel.load()异步从仓库获取并发布items(ByteTest/Core/VideoListViewModel.swift) - 仓库:远程请求 → 工厂映射 → 写入缓存 → 返回(
ByteTest/Core/VideoRepository.swift) - 网络:通用
getDecodable解码 JSON(ByteTest/Core/NetworkClient.swift) - 工厂:将
RemoteVideoInfo转为VideoItem(ByteTest/Core/VideoFactory.swift) - 存储:JSON 原子写入与读取(
ByteTest/Core/DataStorage.swift)
- 两列网格与导航:
ByteTest/UI/ContentView.swift - 卡片封面与信息:
ByteTest/UI/VideoCardView.swift - 播放:
VideoPlayerView全屏播放器AVPlayerViewController(ByteTest/UI/VideoPlayerView.swift) - 点击暂停/继续:透明点击层 + 可点击播放图标(
ByteTest/UI/VideoPlayerView.swift) - 进度条:自定义
UISlider、时间显示与拖动 seek(ByteTest/UI/VideoPlayerView.swift)
- 源与常量:播放源
PlayUrl(HTTPS)在ByteTest/Core/AppConstants.swift;瀑布流数据源VideosFeedUrl指向外部 API(ByteTest/Core/AppConstants.swift)。 - 策略模型:远端优先、写入直通(write-through)、失败回退到本地缓存;缓存采用类型安全的 JSON 文件(
Documents/videos.json)。 - 端到端流程:
- 触发加载:
ContentView出现后调用VideoListViewModel.load()(ByteTest/Core/VideoListViewModel.swift)。 - 拉取远端:仓库在
fetchVideos()中用NetworkClient.getDecodable拉取并解码(ByteTest/Core/VideoRepository.swift,ByteTest/Core/NetworkClient.swift)。
- 触发加载:
- 结构映射:远端
RemoteVideoInfo由工厂转为领域模型VideoItem(ByteTest/Core/VideoFactory.swift)。- 写入缓存:成功获取后即写入 JSON(原子写入避免半写状态)(
ByteTest/Core/DataStorage.swift)。 - 失败回退:网络异常时读取本地缓存,若存在则返回,否则返回空数组(
ByteTest/Core/VideoRepository.swift,ByteTest/Core/DataStorage.swift)。
- 写入缓存:成功获取后即写入 JSON(原子写入避免半写状态)(
- 关键实现:
NetworkClient.getDecodable使用URLSession.shared.data(from:)与HTTPURLResponse状态校验,保障远端返回有效(ByteTest/Core/NetworkClient.swift)。DataStorage.saveVideos原子写入,DataStorage.loadVideos类型安全解码(ByteTest/Core/DataStorage.swift)。VideoRepository.fetchVideos统一编排远端与缓存,屏蔽上层复杂性(ByteTest/Core/VideoRepository.swift)。
- 并发与主线程:
VideoListViewModel使用@MainActor与Task保证 UI 更新在主线程执行,网络与 IO 异步进行(ByteTest/Core/VideoListViewModel.swift)。
- Factory(工厂):
- 角色:将远端结构
RemoteImageInfo转成领域模型VideoItem,统一默认值。 - 实现:
VideoFactory.makeItems(from:)(ByteTest/Core/VideoFactory.swift)。 - 好处:解耦远端数据形态与 UI,便于后续切换数据源或扩充字段。
- 角色:将远端结构
- Singleton(单例):
- 角色:共享无状态或轻状态服务,例如网络与存储。
- 实现:
NetworkClient.shared(ByteTest/Core/NetworkClient.swift),DataStorage.shared(ByteTest/Core/DataStorage.swift)。 - 取舍:便于全局复用,但测试时需支持依赖注入;本项目通过仓库构造函数可覆盖默认单例(
ByteTest/Core/VideoRepository.swift)。
- MVVM:
- 角色:
VideoListViewModel提供可观察状态与加载动作,视图订阅items展示(ByteTest/Core/VideoListViewModel.swift)。 - 好处:分离视图与数据逻辑,便于扩展与测试。
- 角色:
- 类型/文件:大驼峰;变量/方法:小驼峰;常量/枚举成员:大驼峰。
- iOS 16.0+
- Xcode 构建运行,Simulator中运行验证。

