-1

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 structs 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)
Ky -
  • 30,724
  • 51
  • 192
  • 308
  • Include relevant code as part of the question. – Joakim Danielson Jul 02 '23 at 07:11
  • @JoakimDanielson I figured what I included was enough, but I added the class I referenced in the other link in case that's what you meant – Ky - Jul 02 '23 at 23:52
  • Your customer Codable implementation looks very standard, have you tried to see if it works without it? – Joakim Danielson Jul 03 '23 at 07:17
  • What about `MoneySplitter`? What attributes does it have, and what does its `Codable` code look like? – Tom Harrington Jul 03 '23 at 23:39
  • I forgot to add to my previous comment, do you need Codable for something else because otherwise you don't have to conform to it at all. – Joakim Danielson Jul 04 '23 at 05:34
  • @JoakimDanielson I added the conformance to guarantee it conforms at compile-time. My current confusion is why it seems something that should be Codable isn't at runtime – Ky - Jul 07 '23 at 18:11
  • @JoakimDanielson When I comment-out the custom Codable implementation, I get the exact same problem – Ky - Jul 07 '23 at 20:02
  • @TomHarrington https://github.com/KyLeggiero/RentSplitTools/blob/181316d7a37b4b1615d15f10bb2ff2722fab088b/Sources/RentSplitTools/MoneySplitter.swift#L685 – Ky - Jul 07 '23 at 20:02
  • Please add the `MoneySplitter` class/struct to your question. – HangarRash Jul 21 '23 at 02:36
  • Adding custom types (struct/enum) properties to a model class doesn't work very well in the current beta version of SwiftData so this problem really has no other solution than to wait for an update from Apple that resolves the problem. – Joakim Danielson Jul 23 '23 at 09:25
  • @HangarRash added – Ky - Jul 25 '23 at 20:28
  • Thank you, @JoakimDanielson. Since that's the only answer right now, could you please post it so I can accept it until a better answer comes along? – Ky - Jul 25 '23 at 20:29

1 Answers1

1

Adding custom types (struct/enum) properties to a model class doesn't work very well in the current beta version of SwiftData so this problem really has no other solution than to wait for an update from Apple that resolves the problem.

Joakim Danielson
  • 43,251
  • 5
  • 22
  • 52