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

变幻莫测:CoreData 中 Transformable 类型面面俱到(七)

在这里插入图片描述

概述

各位似秃似不秃小码农们都知道,在苹果众多开发平台中 CoreData 无疑是那个最简洁、拥有“官方认证”且最具兼容性的数据库框架。使用它可以让我们非常方便的搭建出 App 所需要的持久存储体系。

在这里插入图片描述

不过,大家是否知道在 CoreData 中还存在一个 Transformable 类型,它到底是个啥?应用场景有哪些?在最新的 SwiftData 中有没有对应物?对于开发者又有哪些“见雀张罗”的撸码陷阱和最佳实践呢?

在本篇博文中,您将学到如下内容:

  • 概述
    • 6.3 Skill 的赋值与读取
    • 6.4 最后一块拼图:实现 SkillTransformer 转换器
  • 总结

本系列文章一共包括将近 3w 枚机智而幽默的文字、详实的大段代码示例以及海量图片,定能让小伙伴们对 Transformable 类型的“驾驭”更加胸有成竹、胜券在握!

那还等什么呢?让我们马上开始 Transformable 大冒险吧!
Let’s go!!!😉


6.3 Skill 的赋值与读取

在上一篇博文中我们已经介绍了 Skill 类及其子类的实现。接下来,我们可以在英雄和恶棍“出生”时为它们增加 Skill 技能啦:

let newHero = Hero(context: context)
newHero.skill = HeroSkill.glarelet newVillain = Villain(context: context)
newVillain.skill = VillainSkill.swallow

当然,别忘了最后需要将这些威力强大的技能“调皮地”显示在视图中哦:

if let skill = villain.skill as? VillainSkill {Section("恶棍技能") {LabeledContent("技能名称") {Text(skill.name)}LabeledContent("邪恶威慑力") {Text("\(skill.evalPower)")}}
}if let skill = hero.skill as? HeroSkill {Section("英雄技能") {LabeledContent("技能名称") {Text(skill.name)}LabeledContent("正义威慑力") {Text("\(skill.justicePower)")}}.foregroundStyle(.red)
}

6.4 最后一块拼图:实现 SkillTransformer 转换器

现在,只剩 Skill 的转换器 SkillTransformer 还未实现了,让我们马上开始搞定它吧!

首先,创建一个 SkillTransformer 类,并让它遵守 NSSecureUnarchiveFromDataTransformer 协议:

class SkillTransformer: NSSecureUnarchiveFromDataTransformer {override class func allowsReverseTransformation() -> Bool {return true}override class func transformedValueClass() -> AnyClass {return Skill.self}override class var allowedTopLevelClasses: [AnyClass] {return [Skill.self, VillainSkill.self, HeroSkill.self, NSString.self]}override func transformedValue(_ value: Any?) -> Any? {guard let data = value as? Data else {fatalError("错误的数据类型")}return super.transformedValue(data)}override func reverseTransformedValue(_ value: Any?) -> Any? {guard let color = value as? Skill else {fatalError("错误的数据类型")}return super.reverseTransformedValue(color)}
}extension NSValueTransformerName {static let skill = NSValueTransformerName(rawValue: "SkillTransformer")
}

不知小伙伴们是否记得,在之前的代码中我们留了一个坑:就是转换器如何把实际需要转换的类型“报备”给系统,这就是上面我们需要重写 allowedTopLevelClasses 计算属性,以返回所需“报备”类的原因了

可以看到,我们不仅返回了 Skill 基类自身,同时还返回了 Skill 所有子类以及其它内置的类型,这样做可以确保系统能会我们的意图“心领神会”。

最后,我们只需在 App 启动的极早期注册 SkillTransformer 类就可以啦:

struct PersistenceController {static let shared = PersistenceController()let container: NSPersistentContainerinit(inMemory: Bool = false) {// 注册 SkillTransformer 转换器ValueTransformer.setValueTransformer(SkillTransformer(), forName: .skill)container = NSPersistentContainer(name: "CDTransformableTest")if inMemory {container.persistentStoreDescriptions.first!.url = URL(fileURLWithPath: "/dev/null")}container.loadPersistentStores(completionHandler: { (storeDescription, error) inif let error = error as NSError? {fatalError("Unresolved error \(error), \(error.userInfo)")}})container.viewContext.automaticallyMergesChangesFromParent = true}
}

注意,如果大家的 App 有一个全局 Model 类型,切勿将 Transformable 转换器放到该类型的构造器中:

class Model: ObservableObject {static let shared = Model()private init() {// 不要这样做!❌ValueTransformer.setValueTransformer(SkillTransformer(), forName: .skill)}
}@main
struct CDTransformableTestApp: App {let model = Model.sharedlet persistenceController = PersistenceController.sharedvar body: some Scene {WindowGroup {MainView().environmentObject(model).environment(\.managedObjectContext, persistenceController.container.viewContext)}}
}

因为就本例来看。这样做会导致 SkillTransformer 在 CoreData 持久容器实例初始化之后才被注册,从而无法起到转换器应有的作用了。

至此,我们已经如约完成了 4 种至 Transformable 的转换场景,在最后一篇博文中,我们将讨论 Transformable 与纯 Data 类型的区别,以及 Transformable 在 SwiftData 里的实现,敬请期待吧!

总结

在本篇博文中,我们收尾了 Skill 及其子类到 Transformable 类型的转换,并实现了 Skill 的转换器 SkillTransformer。

感谢观赏,最后一篇再会吧!😎

http://www.dtcms.com/a/264222.html

相关文章:

  • IDE全家桶专用快捷键----------个人独家分享!!
  • 计算机网络(三)传输层TCP
  • 630,百度文心大模型4.5系列开源!真香
  • Spring Boot 启动加载执行链路分析
  • Spring Boot 集成 Dufs 通过 WebDAV 实现文件管理
  • (第二篇)HMTL+CSS+JS-新手小白循序渐进案例入门
  • C++ 网络编程(13) asio多线程模型IOServicePool
  • Y-Combinator推导的Golang描述
  • 复现一个nanoGPT——model.py
  • postman入门篇
  • 用Fiddler中文版抓包工具掌控微服务架构中的接口调试:联合Postman与Charles的高效实践
  • 2.2.4 Linux 系统日志管理
  • (LeetCode 面试经典 150 题) 42. 接雨水 (单调栈)
  • 【C++】std::vector 全面指南
  • Excel 如何从一个大表里,根据姓名查找到对应的手机号?
  • 【1.5 漫画TiDB分布式数据库】
  • python+uniapp基于微信小程序的流浪动物救助领养系统nodejs+java
  • 蓝牙音频传输协议深度解析:A2DP、HFP、AVRCP 对比与面试核心考点
  • Langgraph 学习教程
  • 日事清驾驶舱模式上线:实时数据更新+项目管理+数据可视化,提升决策效率​
  • 5-TF·IDF关键词算法
  • 强化学习系列--从数值出发,解读 DPO 训练背后的偏好优化逻辑
  • Navicat Premium x TiDB 社区体验活动 | 赢 Navicat 正版授权+限量周边+TiDB 社区积分
  • 第8章路由协议,RIP、OSPF、BGP、IS-IS
  • RabbitMQ简单消息监听
  • 基于开源AI大模型AI智能名片S2B2C商城小程序的流量转化与价值沉淀研究
  • linux魔术字定位踩内存总结
  • 振荡电路Multisim电路仿真实验汇总——硬件工程师笔记
  • MySQL 常用命令大全
  • 0.96寸OLED显示屏 江协科技学习笔记(36个知识点)