Not sure what I'm doing wrong here. I'm taking this opportunity to add persistence to an app that hadn't had it yet.
I followed the WWDC session advice but I get this runtime crash:
SwiftData/BackingData.swift:201: Fatal error: expected attribute to be Codable
The crash is on this line:
modelContext.insert(RentSplitDataModel())
The object being created and inserted there is simple and the compiler confirms it does conform to Codable
:
@Model
public final class RentSplitDataModel {
public var moneySplitter: MoneySplitter
init(_ moneySplitter: MoneySplitter = .init()) {
self.moneySplitter = moneySplitter
}
}
// MARK: - Codable
private extension RentSplitDataModel {
enum CodingKey: String, Swift.CodingKey {
case moneySplitter
}
}
extension RentSplitDataModel: Codable {
public convenience init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKey.self)
self.init(try container.decode(MoneySplitter.self, forKey: .moneySplitter))
}
public func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKey.self)
try container.encode(moneySplitter, forKey: .moneySplitter)
}
}
Here's the relevant code of MoneySplitter
. Full code here (685 lines): https://github.com/KyLeggiero/RentSplitTools/blob/181316d7a37b4b1615d15f10bb2ff2722fab088b/Sources/RentSplitTools/MoneySplitter.swift
/// Performs the heavy-lifting of splitting money across people
public struct MoneySplitter {
/// Everyone participating in this split
public var people: [Person] {
didSet {
recalculateSplit()
}
}
/// All the people participating in this split who live in the home and pay expenses
public var roommates: [Roommate] {
didSet {
recalculateSplit()
}
}
/// All the people are participating in this split who give money to others in this split
public var benefactors: [Benefactor] {
didSet {
recalculateSplit()
}
}
/// All the expenses that the roommates split. Defaults to a reasonable example
public var expenses: [Expense] {
didSet {
recalculateSplit()
}
}
public fileprivate(set) var split = Split(shares: [])
public init(
people: [Person] = .default,
roommates: [Roommate],
benefactors: [Benefactor] = .default,
expenses: [Expense])
{
self.people = people
self.roommates = roommates
self.benefactors = benefactors
self.expenses = expenses
self.recalculateSplit()
}
public init(
people: [Person] = .default,
roommates: [Roommate],
benefactors: [Benefactor] = .default)
{
self.init(people: people,
roommates: roommates,
benefactors: benefactors,
expenses: .default(for: people))
}
public init(
people: [Person] = .default,
benefactors: [Benefactor] = .default,
expenses: [Expense])
{
self.init(
people: people,
roommates: .default(for: people),
benefactors: benefactors,
expenses: expenses
)
}
public init(
people: [Person] = .default,
benefactors: [Benefactor] = .default)
{
self.init(
people: people,
roommates: .default(for: people),
benefactors: benefactors,
expenses: .default(for: people)
)
}
}
// MARK: - Conformance
extension MoneySplitter: Codable {}
Person
, Roommate
, Benefactor
, Expense
, Split
, and AppUniqueIdentifier
are similarly all struct
s conforming to Codable
, boiling down to simple concepts such as numbers and strings
Environment
- macOS Sonoma 14.0 Beta (23A5286i)
- Xcode Version 15.0 beta 4 (15A5195m)
- targeting iOS 17.0 beta 3 (21A5277g)