Adding more than 1 item to "1 to many" property in SwiftData crashes preview / sim

150 views Asked by At

I am trying to setup data in the app during the first launch using SwiftData. If I try to add multiple items to a "1 to many" property, the app crashes.

I am stuck figuring how to make this work. Sample code below:

import SwiftUI
import SwiftData

class Persistance {
    static var previewModelContainer: ModelContainer = {
        let schema = Schema([
            MyList.self,
            MyItem.self,
        ])
        let modelConfiguration = ModelConfiguration(schema: schema, isStoredInMemoryOnly: true)

        do {
            
            let container=try ModelContainer(for: schema, configurations: [modelConfiguration])
            
            //INITING LIST AND ITEMS
            let list=MyList()
            list.name="first list"
            
            let item1=MyItem()
            item1.name="item 1 name"
            print("item1 created")
            
            list.items.append(item1)
            print("item1 added to list")
            
            let item2=MyItem()
            item2.name="item 2 name"
            print("item2 created")
            
            list.items.append(item2)
            print("item2 added to list")
            
            let actor=PersistanceActor(modelContainer: container)
            Task {
                await actor.insert(list)
                print("list added to store")
            }
            
            return container
        } catch {
            fatalError("Could not create ModelContainer: \(error)")
        }
    }()
    
}


actor PersistanceActor: ModelActor {
    let modelContainer: ModelContainer
    let modelExecutor: any ModelExecutor
    
    init(modelContainer: ModelContainer) {
        self.modelContainer = modelContainer
        let context = ModelContext(modelContainer)
        modelExecutor = DefaultSerialModelExecutor(modelContext: context)
    }
    
    func save() {
        do {
            try modelContext.save()
        }catch {
            print("error inserting")
        }
    }

    func insert<T:PersistentModel>(_ value:T) {
        do {
            modelContext.insert(value)
            try modelContext.save()
        }catch {
            print("error inserting")
        }
    }
    
    func delete<T:PersistentModel>(_ value:T) {
        do {
            modelContext.delete(value)
            try modelContext.save()
        }catch {
            print("error inserting")
        }
    }
    
    func get<T:PersistentModel>(_ descriptor:FetchDescriptor<T>)->[T]? {
        var toReturn:[T]?
        do {
            toReturn=try modelContext.fetch(descriptor)
        }catch {
            print("error inserting")
        }
        return toReturn
    }
    
}

@main
struct TestingSDApp: App {
    
    var body: some Scene {
        WindowGroup {
            LaunchUIView()
        }
        .modelContainer(Persistance.previewModelContainer)
    }
}

struct LaunchUIView: View {
    
    @Environment(\.modelContext) private var context
    
    @Query var list:[MyList]
    
    var body: some View {
        VStack {
            ForEach(list, id: \.name) { item in
                MyListItem(item: item)
            }
        }
    }
}

struct MyListItem: View {
    let item:MyList
    var body: some View {
        VStack {
            ForEach(item.items, id: \.self) { item in
                Text("\(item.name ?? "no item name")")
            }
        }
    }
}

#Preview {
    LaunchUIView()
        .modelContainer(Persistance.previewModelContainer)
}

@Model
class MyList {
    
    var name:String?=""
    
    @Relationship(deleteRule: .cascade, inverse: \MyItem.myList)
    var items:[MyItem]=[MyItem]()
    
    init() {
        
    }
}

@Model
class MyItem {
    var name:String?=""
    var myList:MyList?
    
    init() {
        
    }
}

if i comment out the list.items.append(item2) the code seems to work.

Any suggestions highly appreciated.

0

There are 0 answers