parapote
parapote

Reputation: 984

How to persist an OptionSet with SwiftData?

Let's create a simple SwiftData model with a codable OptionSet.

@Model
final class Item {
    var options: SomeOptions
    
    struct SomeOptions: OptionSet, Codable {
        let rawValue: Int
    }
    
    init(options: SomeOptions = .init(rawValue: .random(in: 0..<10))) {
        self.options = options
    }
}

When killing then relaunching the app, all items options rawValues equal 0.

struct ContentView: View {
    @Environment(\.modelContext) private var modelContext
    @Query private var items: [Item]

    var body: some View {
        NavigationStack {
            List(items) { item in
                Text(item.options.rawValue.formatted()) // FIXME: this always diplays "0"
            }
            .toolbar {
                ToolbarItem {
                    Button("Add item", systemImage: "plus", action: addItem)
                }
            }
        }
    }

    private func addItem() {
        withAnimation {
            let newItem = Item()
            modelContext.insert(newItem)
            try! modelContext.save() // FIXME: if not saved, the OptionSet always equals 0 too
        }
    }
}

Any idea of what's going on please?

Tested with Xcode 15.0, targeting iOS 17.

Upvotes: 0

Views: 302

Answers (1)

Joakim Danielson
Joakim Danielson

Reputation: 51973

This looks like a SwiftData bug to me. One workaround for now is to store the raw value of the OptionSet instead and use a transient property of the custom type to access it.

private var optionsStorage: SomeOptions.RawValue

@Transient
var options: SomeOptions {
    get { SomeOptions(rawValue: optionsStorage) }
    set { optionsStorage = newValue.rawValue }
}

We also need to adjust the initialisation

init(options: SomeOptions) {
    self.optionsStorage = options.rawValue
}

Upvotes: 1

Related Questions