I'm trying to understand why SwiftUI Preview won't let me do this:
struct ItemCreateView: View {
@Environment(\.dismiss) var dismiss
@Environment(\.modelContext) private var modelContext
@Query private var collections: [Collection]
let selectedCollection: Collection
@State private var item = Item()
@State private var selectedImage: PhotosPickerItem? = nil
var body: some View {...}
}
#Preview {
let config = ModelConfiguration(isStoredInMemoryOnly: true)
let container = try! ModelContainer(for: Collection.self, configurations: config)
for number in 1...10 {
let col = Collection(name: "Test Collection \(number)")
container.mainContext.insert(col)
}
let selectedCollection = container.mainContext.fetch(Collection.self).first!
ItemCreateView(selectedCollection: selectedCollection).modelContainer(container)
}
The error is:
No exact matches in call to macro 'Preview'
Closure containing control flow statement cannot be used with
result builder 'PreviewMacroBodyBuilder'
However, if I add "Return" to the last item. It'd then complain: Cannot use explicit 'return' statement in the body of result builder 'ViewBuilder'
But everything works if I don't try to fetch a random element from the container.
#Preview {
let config = ModelConfiguration(isStoredInMemoryOnly: true)
let container = try! ModelContainer(for: Collection.self, configurations: config)
for number in 1...10 {
let col = Collection(name: "Test Collection \(number)")
container.mainContext.insert(col)
}
let selectedCollection = Collection(name: "Test Collection 1")
return ItemCreateView(selectedCollection: selectedCollection).modelContainer(container)
}
^ this works.
I'm not sure if I understand the correlation of everything here and I can't seem to find much online regarding that error.
Thank you for your help in advance.
Models for reference
@Model
final class Collection {
var name: String
@Relationship(inverse: \Item.collection) var items: [Item]
var timestamp: Date
init(name: String = "", items: [Item] = [], timestamp: Date = Date()) {
self.name = name
self.items = items
self.timestamp = timestamp
}
}
The code being in a macro, and als in a result builder makes the compiler produce very bad error messages. Let's move everything out of the #Preview
macro, and put it in a regular @ViewBuilder
function.
@ViewBuilder
@MainActor
func f() -> some View {
// everything in #Preview goes here...
}
Now there is an error at the let selectedCollection
line
Cannot convert value of type
Collection.Type
to expected argument typeFetchDescriptor<T>
fetch
doesn't take a metatype. You should pass in a FetchDescriptor<Collection>()
.
Now we get
Call can throw, but it is not marked with 'try' and the error is not handled
So just add try!
.
Finally, there are no more errors, and you can put everything back in the #Preview
.
#Preview {
let config = ModelConfiguration(isStoredInMemoryOnly: true)
let container = try! ModelContainer(for: Collection.self, configurations: config)
for number in 1...10 {
let col = Collection(name: "Test Collection \(number)")
container.mainContext.insert(col)
}
let selectedCollection = try! container.mainContext.fetch(FetchDescriptor<Collection>()).first!
return ItemCreateView(selectedCollection: selectedCollection).modelContainer(container)
}