当前位置: 首页 > news >正文

Core Data与CollectionView UI实时同步:CompositionalDiffablePlayground Jokes示例收藏、上下文菜单与骨架屏动画完整实现

Core Data与CollectionView UI实时同步:CompositionalDiffablePlayground Jokes示例收藏、上下文菜单与骨架屏动画完整实现

【免费下载链接】CompositionalDiffablePlayground.iosExamples showing Compositional Layout, Diffable Data Sources and more!项目地址: https://gitcode.com/gh_mirrors/co/CompositionalDiffablePlayground.ios

CompositionalDiffablePlayground.ios 是一个专门演练 iOS 现代 CollectionView API 的示例工程,核心演示 Compositional Layout(组合式布局)与 Diffable Data Source(可差分数据源)。本文以其中功能最完整的Jokes(笑话列表)示例为主线,拆解Core Data 与 CollectionView UI 实时同步的完整机制,涵盖收藏持久化、长按上下文菜单(朗读/取消收藏)与骨架屏闪烁动画的实现思路,帮助新手理解 Diffable、Compositional 与 Core Data 三者在真实项目中如何协作。

项目概览:现代 CollectionView API 的练习场 🎯

主界面 ViewController.swift 本身也是一个由 Diffable 驱动的 CollectionView,菜单分为两区:

  • Layout 基础示例:列表、简单网格、懒加载网格、吸顶头部、响应式布局、Onboarding 流程等 8 种纯布局玩法;
  • 复杂实战示例:Jokes 笑话列表、Apple Photos 风格画廊(见下方项目自带示例图片)、Instagram 风格个人主页、Indie App 新闻流等。

其中 Jokes 示例是唯一同时串联了网络加载 + Core Data 收藏 + 上下文菜单 + 语音朗读 + 骨架屏的完整场景,因此值得单独拆解。

Core Data 与 CollectionView UI 如何保持实时同步

整个同步链路只由四个角色完成,核心思想是:UI 永远只由 snapshot 驱动,而 snapshot 又永远只从 Core Data 和网络的最新结果构建

角色文件职责
数据库单例Database.swift持有NSPersistentContainer,暴露viewContext,封装saveContext()
数据模型Joke.swiftJoke: NSManagedObject,字段为 id、setup、punchline、created
实体定义contents可视化数据模型中的Joke实体
同步桥JokesViewController.swiftNSFetchedResultsController监听数据库变化

关键在 JokesViewController.swift 末尾这个只有两行的 delegate:

func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChangeContentWith snapshot: NSDiffableDataSourceSnapshotReference) { datasource.apply(self.snapshot(), animatingDifferences: true) }

只要 Core Data 中Joke记录发生增、删、改,NSFetchedResultsController就会回调它;而apply(_:animatingDifferences:)会自动对比新旧快照,只重绘变化的行,并附带原生插入/移除动画。收藏或删除一条记录,UI 在同一个 runloop 内自动刷新——这就是“实时同步”的全部秘密。

一键收藏:快照驱动的 UI 更新 ⭐

收藏入口在 JokesViewController.swift 的两个方法中:

  • favoriteJoke(_:):先用Joke.byIdFetchRequest(id:)查询是否已存在,防止重复收藏,再新建Joke对象写入并saveContext()
  • unfavoriteJoke(withId:):按 id 取出记录后context.delete(_:),同样触发保存。

snapshot()方法每次都直接从fetchedResultsController.fetchedObjects读取最新的收藏列表,构建出favoriteJokes(count:state:)分节——节标题显示Favorites (n),并可通过ActionButtonHeader按钮整体展开/折叠。

两个细节值得注意:

  1. Joke.Diffablehash(into:)只合并id(见 Joke.swift),保证 Diffable 算法能正确识别“同一条笑话”,内容变化不会误判为增删;
  2. JokeCell.swift 根据数据来源切换星形图标:来自网络的显示空心星(可收藏),来自 Core Data 的显示实心星(已收藏),一眼区分两种状态。

长按上下文菜单:把笑话读出来 🎙️

长按菜单由 JokesViewController.swift 的contextMenuConfigurationForItemAt实现,逻辑简洁:

  • 先通过datasource.itemIdentifier(for:)反查当前 item,骨架屏占位项(.loading)直接返回 nil 不显示菜单
  • 固定提供Hear动作:用AVSpeechSynthesizer朗读setup + punchline
  • 仅当 item 属于收藏分节时,额外追加Unfavorite动作,调用前面提到的删除逻辑。

由于删除会走 Core Data 保存 → FRC 回调 →apply(snapshot)的全链路,菜单里的“取消收藏”同样享受自动 diff 动画,无需手写任何刷新代码。

![CollectionView 骨架屏加载示例的项目内置头像示例图](https://raw.gitcode.com/gh_mirrors/co/CompositionalDiffablePlayground.ios/raw/7bbc7612548ffe6d8b11906fdf376ccdd0987153/CompositionalDiffablePlayground/CompositionalDiffablePlayground/Assets.xcassets/mockAvatar.imageset/Screenshot 2021-01-16 at 14.25.55.png?utm_source=gitcode_repo_files)

骨架屏闪烁动画:20 行代码做出 shimmer 效果 ⚡

数据未返回时,snapshot()会向.jokes分节填入 8 个Item.loading(UUID)占位项(每个 UUID 独立,避免复用同一身份),cell 分支中调用showLoading()(见 JokeCell.swift):

  1. 创建一个CAGradientLayer,颜色为透明 → 10% 黑色 → 透明,宽度放大 3 倍并左移,作为“光带”;
  2. CABasicAnimation动画locations属性从[0.0, 0.1, 0.2][0.8, 0.9, 1.0]duration = 1.1repeatCount = .infinity,得到循环扫过的 shimmer 效果;
  3. prepareForReuse()中执行shimmerLayer?.removeFromSuperlayer()防止 cell 复用时残留动画

这套“占位 item + 渐变光带动画 + 复用时清理”的组合,可以直接迁移到任何 Diffable 列表。

关键文件路径速查表

功能模块文件路径
笑话列表控制器(快照/FRC 同步/上下文菜单)ViewControllers/JokesViewController.swift
骨架屏 shimmer 动画单元格Views/JokeCell.swift
网络笑话 DTOModel/DTO/JokeDTO.swift
共享协议(setup/punchline)Protocols/JokeProtocol.swift
Core Data 实体与排序请求Database/Joke.swift
持久层单例Database/Database.swift
实体模型文件Database.xcdatamodel/contents
网络请求(official-joke-api)Networking/SimpleNetworkHelper.swift
通用排序请求扩展Database/Managed.swift

获取项目并运行 🚀

执行以下命令克隆仓库,用 Xcode 打开工程,选择 iOS 13+ 模拟器运行即可(Jokes 需要网络访问笑话 API):

git clone https://gitcode.com/gh_mirrors/co/CompositionalDiffablePlayground.ios

运行后在主页第二个分节点击Jokes list即可体验完整效果:进入时先看到 8 格 shimmer 骨架屏,加载完成后逐行动画填充;点星形收藏会实时出现在顶部 Favorites 分节;长按任意一条笑话可朗读或取消收藏。对照文中四个核心文件阅读源码,是掌握Core Data 与 CollectionView 实时同步的最佳路径。

【免费下载链接】CompositionalDiffablePlayground.iosExamples showing Compositional Layout, Diffable Data Sources and more!项目地址: https://gitcode.com/gh_mirrors/co/CompositionalDiffablePlayground.ios

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

http://www.cnnetsun.cn/news/4173434.html

相关文章:

  • BreezeJS快速上手指南:在CustomerManagerStandard中掌握EntityManager、元数据获取与saveChanges完整工作流
  • 嵌入式学习路线全解析:从51单片机到STM32,新手避坑指南与核心技能构建
  • 数学建模实战:线性回归的核心假设、特征工程与模型诊断全解析
  • Vortigern 样式方案拆解:CSS Modules + PostCSS-Assets 完整配置指南
  • 深入react-native-app-tour源码:findNodeHandle与NativeModules如何打通JS与原生App Tour视图
  • 为什么DebugKit是Android开发者必备的悬浮调试神器?完整概览与功能解析
  • noteForOpenGL PBO像素缓冲对象:Pack/Unpack机制与CPU-GPU数据通道完整指南
  • 函数设计四大核心特性:从内置函数到模板重载的工程实践
  • OpCore-Simplify 快速上手指南:从硬件报告到 OpenCore EFI
  • Android开发者必学:从file_operations入门Linux驱动开发
  • 如何测试行级权限控制?用 pytest 与 pytest-mock 构建 fastapi-permissions 单元测试完全指南
  • 数学建模实战指南:从思维转变到模型落地的全流程解析
  • 开发者知识体系重构:从碎片化学习到系统化升级的工程实践
  • 5分钟跑通pymavlink:mavlink_connection连接Pixhawk并接收心跳的保姆级实战
  • 多智能体集群架构:构建公平、自适应的心理健康支持系统
  • 彻底解决链接器报错:从原理到实战的完整指南
  • RogueViz引擎深度剖析:HyperRogue背后的非欧几何游戏引擎
  • 30 分钟跑通 openAUTOSAR 经典平台:3 个核心模块与 1 个必踩的坑
  • 人形机器人落地实战:工业、商用、家庭三大场景技术评估与集成指南
  • RESTful API设计最佳实践与Python工程化实战指南
  • 花多少钱能买齐OpenArm的零件?BOM成本完整拆解与低价采购攻略
  • cargo-call-stack 源码解析指南:用 nom 手写 LLVM IR 解析器,构建全程序调用图
  • 从数学建模到量化交易:基于MCM赛题的策略开发全流程解析
  • 泰拉瑞亚灾厄Mod完整安装指南:从版本选择到汉化排错
  • 2026年硬盘盒选购指南:从SATA到NVMe协议,实测16款主流产品
  • unicode-segmentation如何实现UAX29标准:剖析GraphemeCursor状态机与GB规则判定逻辑
  • personal-jekyll-theme源码架构全解析:Jekyll布局、Liquid模板与组件化设计实战
  • HyperRogue的.tes镶嵌文件格式完全指南:定义并加载你的自定义几何
  • 计算机考研408核心考点:虚拟内存地址转换机制深度解析与真题实战
  • 机器人应用泛化:从汽车产线到千行百业的技术变革与实践指南