No Observable Object of type...found

I am learning SwiftUI.

Error: SwiftUI/Environment+Objects.swift:32: Fatal error: No Observable object of type ViewModel found. A View.environmentObject(_:) for ViewModel may be missing as an ancestor of this view.

I do not get the point why this happens. The error is shown in the line : "renderer.render {...

import SwiftData
import SwiftUI

@Observable
class ViewModel {
    
    var groupNumber: String = "Gruppe"
    
    var sumOfHours: Int = 0
    
    var personsToPrint: [Person]? = nil
    
    @MainActor func pdfReport(person: [Person]) {
        if personsToPrint != nil {

            for person in personsToPrint! {
                let renderer = ImageRenderer(content: PersonDetailView(person: person))
                let url = URL.documentsDirectory.appending(path: "\(person.lastname) \(person.firstname).pdf")
                print(person.lastname, person.firstname)
                
                renderer.render { size, context in
                    var box = CGRect(x: 0, y: 0, width: size.width, height: size.height)
                    guard let pdf = CGContext(url as CFURL, mediaBox: &box, nil) else {
                        return
                    }
                    pdf.beginPDFPage(nil)
                    context(pdf)
                    pdf.endPDFPage()
                    pdf.closePDF()
                    
                    let data = try! Data(contentsOf: url) //pdf muss erst in Daten umgewandelt werden.
                    do {
                        try data.write(to: url)
                        print("Daten wurden hier gespeichert: \(url)")
                        
                    } catch {
                        print("PDF could not be saved!")
                    }
                }
            }
        }
    }
    
    

}

Replies

I have not used the Observation framework or SwiftUI's image renderer, but I think you need to move your pdfReport function out of the view model and into a SwiftUI view. I don't think you can create the image renderer in a view model.

One question about your code. Why do you pass an array of Person objects to pdfReport and have the personsToPrint property in the ViewModel class? You don't use the person argument in the pdfReport function.

Wouldn't it be easier to get rid of the personsToPrint property and use the array of Person objects in the for loop? Then you wouldn't have to worry about the array being nil.

@MainActor func pdfReport(people: [Person]) {
  for person in people {
    // Rest of code omitted
  }
}