When uncomment TextField("Name:", text: $editedModel.name)
canvas preview crashes with no log...
@Model
final class Item {
var name: String
var value: Double?
var isCheckable: Bool = true
init(name: String, value: Double? = nil) {
self.name = name
self.value = value
}
}
struct EditItemView: View {
@Bindable var editedModel: Item
@State var temp: String = ""
private let editModelContext: ModelContext
init(item: Item, container: ModelContainer){
editModelContext = ModelContext(container)
editModelContext.autosaveEnabled = false
editedModel = editModelContext.model(for: item.id) as! Item
}
var body: some View {
VStack{
TextField("Name:", text: $temp)
// TextField("Name:", text: $editedModel.name)
Toggle("Checkable", isOn: $editedModel.isCheckable)
}
.onDisappear{
try! editModelContext.save()
}
}
}
#Preview {
EditItemView(item: Item(name:"Preview item"), container: try! ModelContainer(for:Item.self))
}
Any idea why?
This seems to be caused by an (old) bug and can either be resolved as in this answer or another solution is to give name a default value in the model since
var name: String = ""
but if you don't want to change the model for a Preview/SwiftData bug a third option that is a bit more work but that might be more useful in the long run is to create a specific type to create and hold a ModelContainer instance for all your preview use.
final class PreviewSingleton: Sendable {
static let shared = PreviewSingleton()
let container: ModelContainer
private init() {
let config = ModelConfiguration(isStoredInMemoryOnly: true)
container = try! ModelContainer(for: Item.self, configurations: config)
buildTestData()
}
private func buildTestData() {
let context = ModelContext(container)
let item = Item(name:"Preview item")
context.insert(item)
try? context.save()
}
func fetchFirst() -> Item? {
let context = ModelContext(container)
return try? context.fetch(FetchDescriptor<Item>()).first
}
}
Note that I create a configuration for in-memory use rather and also note that if you want to add more model types the fetchFirst
and similar fetch functions can easily be made generic.
Then use this singleton (feel free to give it a better name :)) in the preview
#Preview {
if let item = PreviewSingleton.shared.fetchFirst() {
return EditItemView(item: item, container: PreviewSingleton.shared.container)
} else {
return Text("No test data")
}
}