当前位置: 首页 > 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.lryc.cn/news/578589.html

相关文章:

  • 打造 AI 产品的前端架构:响应式、流式、智能交互三合一
  • 基于SSM万华城市货运服务系统的设计与实现
  • OpenCV CUDA模块设备层-----反向二值化阈值处理函数thresh_binary_inv_func()
  • Python学习Day48
  • golang generic 2022-04-13
  • 技术学习_人工智能_1_神经网络是如何实现的?
  • IDE全家桶专用快捷键----------个人独家分享!!
  • 02.SpringBoot常用Utils工具类详解
  • pytorch学习—7.处理多维特征的输入
  • 通达信【极弱强势指标与股道波段交易系统】幅图
  • 【学习笔记】Python中主函数调用的方式
  • 修改Spatial-MLLM项目,使其专注于无人机航拍视频的空间理解
  • Electron 应用中的内容安全策略 (CSP) 全面指南
  • AbMole| H₂DCFDA(M9096;活性氧(ROS)探针)
  • 医学编码:临床试验数据标准化的关键
  • Next.js 安装使用教程
  • 多容器应用与编排——AI教你学Docker
  • Web性能测试常用指标(转自百度AI)
  • 开关电源和线性电源Multisim电路仿真实验汇总——硬件工程师笔记
  • 暖通锅炉的智能管控:物联网实现节能又舒适​
  • grom使用mysql快速上手
  • [论文阅读] 人工智能 + 软件工程 | 从软件工程视角看大语言模型:挑战与未来之路
  • 使用 icinga2 写入 TDengine
  • 基于ApachePOI实现百度POI分类快速导入PostgreSQL数据库实战
  • SpringBoot计时一次请求耗时
  • 基于netmiko模块实现支持SSH or Telnet的多线程多厂商网络设备自动化巡检脚本
  • 浏览器F12开发者工具的使用
  • [Python] -基础篇7-新手常见Python语法错误及解决方案
  • Qt时间显示按钮功能详解
  • openlayers根据图层名称判断图层是否在视口内