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

不过,大家是否知道在 CoreData 中还存在一个 Transformable 类型,它到底是个啥?应用场景有哪些?在最新的 SwiftData 中有没有对应物?对于开发者又有哪些"见雀张罗"的撸码陷阱和最佳实践呢?
在本篇博文中,您将学到如下内容:
本系列文章一共包括将近 3w 枚机智而幽默的文字、详实的大段代码示例以及海量图片,定能让小伙伴们对 Transformable 类型的"驾驭"更加胸有成竹、胜券在握!
那还等什么呢?让我们马上开始 Transformable 大冒险吧!
Let's go!!!😉
5. 异构自定义结构
承前所述,所谓"异构"自定义结构,就是同一个 Transformable 字段中需要存放不同自定义结构的值,这看起来"疑云重重",其实也异常简单。
基本思路是:将不同结构统统转换为 Data 类型,然后按照实际情况把它们解析回原来正确的结构。
首先,在 Record 字段中新增 usingMagic 字段,不出意外它的类型是 Transformable:

随后,我们分别创建 HeroMagic 和 VillainMagic 两个结构类型:
swift
struct HeroMagic: Codable {
let cooperationFormulaName: String
let collaboratorName: String
static func toMagic(_ data: Data) throws -> HeroMagic {
let decoder = JSONDecoder()
return try decoder.decode(HeroMagic.self, from: data)
}
func toData() throws -> Data {
let encoder = JSONEncoder()
let data = try encoder.encode(self)
return data
}
}
struct VillainMagic: Codable {
let powerOfEvilGate: Int
let gateName: String
static func toMagic(_ data: Data) throws -> VillainMagic {
let decoder = JSONDecoder()
return try decoder.decode(VillainMagic.self, from: data)
}
func toData() throws -> Data {
let encoder = JSONEncoder()
let data = try encoder.encode(self)
return data
}
}
接着,我们需要在英雄和恶棍战斗(fight)之后,为其产生的 Record 增加魔法使用记录:
swift
extension Human {
func fight() throws {
let context = managedObjectContext!
let record = Record(context: context)
record.date = .now
record.result = .random()
record.owner = self
// 为英雄和恶棍添加魔法支援
if self is Hero {
let magic = HeroMagic(cooperationFormulaName: FormulaNames.randomElement()!, collaboratorName: HeroNames.randomElement()!)
record.usingMagic = try magic.toData() as NSObject
} else if self is Villain {
let magic = VillainMagic(powerOfEvilGate: Int.random(in: 1...10), gateName: GateNames.randomElement()!)
record.usingMagic = try magic.toData() as NSObject
}
let numbers = makeRandomNumbers()
record.randomNumbers = numbers as NSObject
try context.save()
}
}
最后,我们只需在 SwiftUI 视图中增加对应魔法的显示即可大功告成:
swift
// For 英雄:
if let data = record.usingMagic as? Data {
let magic = try! HeroMagic.toMagic(data)
GroupBox("使用的魔法") {
LabeledContent("协助者") {
Text(magic.collaboratorName)
}
LabeledContent("协作契约配方") {
Text("\(magic.cooperationFormulaName)")
}
}
}
// For 恶棍:
if let data = record.usingMagic as? Data {
let magic = try! VillainMagic.toMagic(data)
GroupBox("使用的魔法") {
LabeledContent("邪恶入口") {
Text(magic.gateName)
}
LabeledContent("入口孽障值") {
Text("\(magic.powerOfEvilGate)")
}
}
}
在上面的代码中,我们根据英雄或恶棍的不同,妥善的将记录使用的魔法转换到对应的魔法类型(HeroMagic 或 VillainMagic)上。
如您所见,我们现在可以妥妥的浏览英雄或恶棍战斗时所使用的魔法啦,棒棒哒💯:

在下一篇博文中,我们将继续聊聊如何让派生自 NSObject 的自定义类支持 Transformable 类型,敬请期待吧!
总结
在本篇博文中,我们介绍了异构自定义结构的值转换到 Transformable 类型的方法,大量的代码示例必定让小伙伴们受益良多。
感谢观赏,我们下一篇再会吧!😎