SwiftData Predicates crashes when using Generic

I have been dealing with an error for almost 2 days now that caused my programme to crash on runtime with Thread 10: EXC_BAD_ACCESS (code=1, address=0x0) error , only when using Release mode.

After many trial and errors and narrowing down the root problem I became suspicious to #Predicate and Generics being the root cause of the problem so I made these views to test it out.

import SwiftUI
import SwiftData
struct DataBaseTestGeneric<Model : PersistentModel>: View {
    @State private var models: [Model] = []
    var body: some View {
        viewLoader{
          
           
            let reporter = Reporter()
            let pred = #Predicate<Model>{ model in
                return true
            }
            models =  await reporter.fetch(pred)

        }content: {
           
            List{
                ForEach(models){ model in
                    Text("\(model.id)")
                }
            }
            
        }
    }
}

and a non-Generic version :

import SwiftData

struct DatabaseTest: View {

    @State private var transactions: [Transaction] = []
    var body: some View {
        viewLoader {
            let reporter = Reporter()
            let pred = #Predicate<Transaction>{ dec in
                return true
            }
            let decs =  await reporter.fetch(pred)
            transactions = decs
        }content:{
            List{
                ForEach(transactions){transaction in
                    Text("\(transaction.id)")
                }
            }
        }
          
    }
}

to give you an insight viewLoader implentations is :

struct viewLoader<Content : View>: View {
    
    var state : LoadingView.States = .loading
    let loadingTask : () async -> Void
    @State private var isLoading = true
    
    @ViewBuilder var content : Content
    
    var body: some View {
        if isLoading{
            LoadingView(state)
                .task {
                  await  Task.detached(priority:.high){
                        await loadingTask()
                        
                  }.value
                    isLoading = false
                }
        }else{
            content
        }
    }
}

and I am accessing SwiftData using a background thread ( by implementing @ModelActor . the problem is that the code always crash on runtime when I am trying to fetch the data using reporter.fetch function. To make things even more weird I have to add the fact that Reporter class also have another function called fetchAll as follow :

 func fetchAll<T>(_ model : T.Type) async -> [T] where T : PersistentModel {
        let desc = FetchDescriptor<T>()
        let result = try? await context.fetch(desc)
        guard let result else {
            assertionFailure("Error fetching \(model) from context")
            return []
        }
        return result
    }

if i replace this function with reporter.fetch (which takes a predicate) the code will not crash either with or without using Generics , which brings me to the point that #Predicate is causing mayhem somehow !

PS: I am using Xcode Version 16.1 (16B40) , on macOs Sequoia Version 15.2 Beta (24C5089c)

Answered by joadan in 816841022

There's a lot I don't understand about your question like what Reporter really is, how the ModelActor comes into play and what you mean with the last paragraph about the fetchAll method (did you write a "not" to much?) but one issue I see in your code is that you are passing PersistentModel objects from the detached Task to the UI which means you are passing them across actor boundaries and that is something you should not do since they are not conforming to Sendable. (Which swift version are you using and do you have any concurrency checking set?)

This makes the whole solution look flawed and I would suggest that you instead fetch your objects on the MainActor using a @Query instead.

I forgot to mention that the code only crashes for the Generic version , the non Generic version always succeeds regardless.

Accepted Answer

There's a lot I don't understand about your question like what Reporter really is, how the ModelActor comes into play and what you mean with the last paragraph about the fetchAll method (did you write a "not" to much?) but one issue I see in your code is that you are passing PersistentModel objects from the detached Task to the UI which means you are passing them across actor boundaries and that is something you should not do since they are not conforming to Sendable. (Which swift version are you using and do you have any concurrency checking set?)

This makes the whole solution look flawed and I would suggest that you instead fetch your objects on the MainActor using a @Query instead.

SwiftData Predicates crashes when using Generic
 
 
Q