I have a set of cascading dependent models. I want to create a preview container that adds them all to a preview container. I have created a model container which loads a recipe of my choice in sequentialy so the instantiation works. I noticed that everything loads but only 1 RecipeStep will ever be added. No matter how I do it, only one is added (randomly).
What is the best practice for creating a swiftdata preview with dependent models? How can I put them in a struct / class for easy access? I tried making a class that initialized the whole swiftdata object however the preview crashes when using this.
Note: I know one solution is that I could make child to parent fields optional, but I don't want to do that since I need them required.
@Model
class CocktailRecipe {
@Attribute(.unique) var id: UUID
@Attribute(.unique) var name: String
var info: String?
var menu: CocktailMenu?
@Relationship(deleteRule: .cascade, inverse: \Ingredient.recipe)
var ingredients: [Ingredient]
@Relationship(deleteRule: .cascade, inverse: \RecipeSection.recipe)
var sections: [RecipeSection]
var created_at: Date
init(name: String, info: String? = nil, menu: CocktailMenu? = nil, sections: [RecipeSection] = [], ingredients: [Ingredient] = []) {
self.name = name
self.info = info
self.menu = menu
self.sections = sections
self.ingredients = ingredients
self.created_at = Date()
self.id = UUID()
}
}
@Model
class Ingredient {
@Attribute(.unique) var id: UUID
@Attribute(.unique) var name: String
var quantity: Float?
var units: IngredientUnitType
var type: IngredientType
var recipe: CocktailRecipe
var created_at: Date
init(name: String, quantity: Float? = nil, units: IngredientUnitType, type: IngredientType, recipe: CocktailRecipe) {
self.name = name
self.quantity = quantity
self.units = units
self.type = type
self.recipe = recipe
self.created_at = Date()
self.id = UUID()
}
}
@Model
class RecipeSection {
@Attribute(.unique) var id: UUID
@Attribute(.unique) var title: String?
@Attribute(.unique) var index: Int
@Relationship(deleteRule: .cascade, inverse: \RecipeStep.section)
var steps: [RecipeStep]
var recipe: CocktailRecipe
var created_at: Date
init(title: String? = nil, recipe: CocktailRecipe, steps: [RecipeStep] = []) {
self.title = title
self.recipe = recipe
self.index = recipe.sections.count + 1
self.steps = steps
self.created_at = Date()
self.id = UUID()
}
}
@Model
class RecipeStep {
@Attribute(.unique) var id: UUID
@Attribute(.unique) var instruction: String
@Attribute(.unique) var index: Int
var section: RecipeSection
var created_at: Date
init(instruction: String, section: RecipeSection) {
self.instruction = instruction
self.section = section
self.index = section.steps.count + 1
self.created_at = Date()
self.id = UUID()
}
}
let cocktailPreviewContainer: ModelContainer = {
do {
let container = try ModelContainer(
for: CocktailMenu.self, CocktailRecipe.self, Ingredient.self, RecipeSection.self, RecipeStep.self, /*Bottle.self, Bar.self, */
configurations: ModelConfiguration(isStoredInMemoryOnly: true)
)
let modelContext = container.mainContext
let spicyMargarita = CocktailRecipe(name: "Spicy Margarita")
modelContext.insert(spicyMargarita)
// Initialize ingredients
let spicyMargaritaIngredients = [
Ingredient(name: "Tequila", quantity: 2, units: .ounces, type: .tequila, recipe: spicyMargarita),
Ingredient(name: "Lime Juice", quantity: 1, units: .ounces, type: .mixer, recipe: spicyMargarita),
Ingredient(name: "Agave Syrup", quantity: 0.5, units: .ounces, type: .mixer, recipe: spicyMargarita),
// Ingredient(name: "Jalapeno", quantity: 3, units: .slices, type: .garnish, recipe: spicyMargarita)
]
for ingredient in spicyMargaritaIngredients {
modelContext.insert(ingredient)
}
try? modelContext.save()
// Initialize sections and steps
let preparationSection = RecipeSection(title: "title here", recipe: spicyMargarita)
modelContext.insert(preparationSection)
try? modelContext.save()
let step1 = RecipeStep(instruction: "Muddle the jalapeno slices in the shaker.", section: preparationSection)
modelContext.insert(step1)
let step2 = RecipeStep(instruction: "Add tequila, lime juice, and agave syrup to shaker with ice.", section: preparationSection)
modelContext.insert(step2)
let step3 = RecipeStep(instruction: "Shake well.", section: preparationSection)
modelContext.insert(step3)
let step4 = RecipeStep(instruction: "Strain into a chilled glass.", section: preparationSection)
modelContext.insert(step4)
return container
} catch {
fatalError("Failed to create container")
}
}()
var spicyMargarita: CocktailRecipe
init() {
// Initialize spicyMargarita recipe
spicyMargarita = CocktailRecipe(name: "Spicy Margarita")
// Initialize ingredients
let tequila = Ingredient(name: "Tequila", quantity: 2, units: .ounces, type: .tequila, recipe: spicyMargarita)
let limeJuice = Ingredient(name: "Lime Juice", quantity: 1, units: .ounces, type: .mixer, recipe: spicyMargarita)
let agaveSyrup = Ingredient(name: "Agave Syrup", quantity: 0.5, units: .ounces, type: .mixer, recipe: spicyMargarita)
let jalapeno = Ingredient(name: "Jalapeno", quantity: 3, units: .slices, type: .garnish, recipe: spicyMargarita)
// Initialize sections and steps
let preparationSection = RecipeSection(recipe: spicyMargarita)
let preparationSteps = [
RecipeStep(instruction: "Muddle the jalapeno slices in the shaker.", section: preparationSection),
RecipeStep(instruction: "Add tequila, lime juice, and agave syrup to shaker with ice.", section: preparationSection),
RecipeStep(instruction: "Shake well.", section: preparationSection),
RecipeStep(instruction: "Strain into a chilled glass.", section: preparationSection)
]
// WHEN THE BELOW IS COMMENTED OUT, no errors, but have many missing objects.
spicyMargarita.ingredients.append(contentsOf: [tequila, limeJuice, agaveSyrup, jalapeno])
spicyMargarita.sections.append(preparationSection)
preparationSection.steps.append(contentsOf: preparationSteps)