Al construir una aplicación con base de datos, resulta conveniente inyectar algo de información en el Preview en la base de datos, no de forma persistente sino en memoria.
Para esto podría directamente crear una fábrica para el ModelContainer que solo se compile en DEBUG, como ilustro a continuación:
#if DEBUG
enum ContainerFactory {
static func create() -> ModelContainer {
let container = try! ModelContainer(for: Model1.self, Model2.self, Model3.self, configurations: .init(isStoredInMemoryOnly: true))
let context = container.mainContext
// Preview seed data
for i in 0..<Int.random(in: 1..<5) {
let newItem = Model1(...)
context.insert(newItem)
}
for i in 0..<Int.random(in: 1..<3) {
let newItem = Model2(...)
context.insert(newItem)
}
for i in 0..<Int.random(in: 1..<4) {
let newItem = Model3(...)
context.insert(newItem)
}
try? context.save()
return container
}
}
#endif
Luego, en el Preview podría hacer uso de la fábrica de este modo:
#Preview {
let container = ContainerFactory.create()
return ContentView()
.modelContainer(container)
}
Aunque la aproximación funciona, SwiftUI también ofrece una estrategia un poco más limpia para hacer la creación e inyección de estas dependencias en el Preview por medio de PreviewModifier. Para ello solo hay que conformar el protocolo en una struct, definir el typealias para Context y luego implementar los métodos makeSharedContext() (donde se construye el contexto) y body(content:context:) (donde se lo inyecta). Por ejemplo:
struct PreviewData: PreviewModifier {
typealias Context = ModelContainer
static func makeSharedContext() async throws -> ModelContainer {
return ContainerFactory.create()
}
func body(content: Content, context: Context) -> some View {
content
.modelContainer(context)
}
}
Notar que en el caso anterior, en body(content:context:) estoy inyectando la dependencia ModelContainer por medio de .modelContainer y que el tipo de la variable es Context. No confundir ese Context, que es un associated type de PreviewModifier con ModelContext de SwiftData.
Aunque puede parecer tentador poner todo el código de construcción dentro de makeSharedContext(), recordar que esa no necesariamente es su responsabilidad, y que se puede extraer en una fábrica.
Luego, se puede usar la struct que conforma PreviewModifier en un Preview por medio del trait modifier(_:):
#Preview(traits: .modifier(PreviewData())) {
ContentView()
}
Top comments (0)