Using Generic SwiftData Modules

Hi, I have the view below that I want it to get any sort of SwiftData model and display and string property of that module, but I get the error mentioned below as well, also the preview have an error as below, how to fix it ? I know its little complicated.

  1. Error for the view GWidget

" 'init(wrappedValue:)' is unavailable: The wrapped value must be an object that conforms to Observable "

  1. Error of preview

" Cannot use explicit 'return' statement in the body of result builder 'ViewBuilder' "

3, Code

#Preview {
    do {
        let configuration = ModelConfiguration(isStoredInMemoryOnly: true)
        let container = try ModelContainer(for: Patient.self, configurations: configuration)
        
        let example = Patient(firstName: "Ammar S. Mitoori", mobileNumber: "+974 5515 7818", homePhone: "+974 5515 7818", email: "ammar.s.mitoori@gmail.com", bloodType: "O+")
        
        // Pass the model (Patient) and the keyPath to the bloodType property
        return GWidget(model: example, keyPath: \Patient.bloodType)
            .modelContainer(container)
        
    } catch {
        fatalError("Fatal Error")
    }
}

4. Code for the Gwidget View

```import SwiftUI
import SwiftData


struct GWidget<T>: View {
    @Bindable var model: T
    var keyPath: KeyPath<T, String> // Key path to any string property

    // Variables for the modified string and the last character
    var bloodTypeWithoutLast: String {
        let bloodType = model[keyPath: keyPath]
        return String(bloodType.dropLast())
    }
    
    var lastCharacter: String {
        let bloodType = model[keyPath: keyPath]
        return String(bloodType.suffix(1))
    }
    
    var body: some View {
        VStack(alignment: .leading) {
            Text("Blood Type")
                .font(.footnote)
                .foregroundStyle(sysPrimery07)
            
            HStack (alignment: .lastTextBaseline) {
                Text(bloodTypeWithoutLast)
                    .fontWeight(.bold)
                    .font(.title2)
                    .foregroundStyle(sysPrimery07)
                
                VStack(alignment: .leading, spacing: -5) {
                    Text(lastCharacter)
                        .fontWeight(.bold)
                    Text(lastCharacter == "+" ? "Positive" : "Negative")
                }
                .font(.caption2)
                .foregroundStyle(lastCharacter == "+" ? .green : .pink)
            }
        }
    }
}

Answered by DTS Engineer in 812717022

" 'init(wrappedValue:)' is unavailable: The wrapped value must be an object that conforms to Observable "

With this message, the compiler is telling you that model is not Observable. You can fix that by telling the compiler that T is a SwiftData model type, as shown below:

struct GWidget<T: PersistentModel>: View {
    @Bindable var model: T

" Cannot use explicit 'return' statement in the body of result builder 'ViewBuilder' "

I don't see this error on my side. I guess this will go away after you fix the first error.

Best,
——
Ziqiao Chen
 Worldwide Developer Relations.

" 'init(wrappedValue:)' is unavailable: The wrapped value must be an object that conforms to Observable "

With this message, the compiler is telling you that model is not Observable. You can fix that by telling the compiler that T is a SwiftData model type, as shown below:

struct GWidget<T: PersistentModel>: View {
    @Bindable var model: T

" Cannot use explicit 'return' statement in the body of result builder 'ViewBuilder' "

I don't see this error on my side. I guess this will go away after you fix the first error.

Best,
——
Ziqiao Chen
 Worldwide Developer Relations.

Ok now the solution you suggested raised few more questions and errors as below ..

  1. Now to use the T with text such as Text(T.age) it will complain that T doesn't have no age property ?

  2. Now suppose I want even the property of the T to be also generic and passed to the view as argument how we do it like T.T ? can I see an example ? Im trying to make a generic view that shows any property of any SwiftData module.

  3. Also #Preview is compiling that the generic variable isn't initialized and I wonder how can we initialize a generic variable ?

I get the error .. Missing argument for parameter 'dataModule' in call

import SwiftUI
import SwiftData


struct GenderList2<T: PersistentModel>: View {
    @Bindable var dataModule: T
   
    var body: some View {
        HStack(alignment: .top) {
            Text(T.age)
        }
    }
}

#Preview {
    GenderList2()
}

@DTS Engineer I think the code below works, ill keep testing and update you,

import SwiftUI
import SwiftData


struct SwiftUIView<T: PersistentModel>: View {
    @Bindable var dataModule: T
    var keyPath: KeyPath<T, String>
    
    var body: some View {
        HStack(alignment: .top) {
            Text(dataModule[keyPath: keyPath])
        }
    }
}


#Preview {
    do {
        let configuration = ModelConfiguration(isStoredInMemoryOnly: true)
        let container = try ModelContainer(for: Patient.self, configurations: configuration)
        
        let example = Patient(firstName: "First Name", mobileNumber: "+974 1234 5678", homePhone: "+974 1234 5678", email: "firstname.lastname@gmail.com")
        
        return  SwiftUIView(dataModule: example, keyPath: \.firstName)
            .modelContainer(container)
        
    } catch {
        fatalError("Fatal Error")
    }
}
Using Generic SwiftData Modules
 
 
Q