ios – SwiftUI Task is blocking UI


I am trying to render a complex view and create and display a pdf from that rendered content.

I initiate this by pressing a button and when the task is complete I want to display a sheet with the pdf.

I want to show a progressView during this process however I am noticing that the Main UI is being blocked despite the Task / Async / Await with SwiftUI.

Below is a minimally reproduced example of what I am trying to achieve:

struct ContentView: View {
    
    let array = ["one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eighteen", "nineteen", "twenty"]
    
    @State var hideProgressView = true
    @State var pdfURL: URL?
    
    var body: some View {
        VStack {
            if !hideProgressView {
                ProgressView()
                    .progressViewStyle(.circular)
                    .padding(.bottom)
            }
            Button {
                hideProgressView = false
                Task {
                    await renderView()
                    hideProgressView = true
                    // show pdf
                }
            } label: {
                Text("Generate PDF")
            }
            .buttonStyle(.borderedProminent)
        }
    }
    
    @MainActor
    func renderView() async {

        let url = URL.documentsDirectory.appending(path: "output.pdf")
        var box = CGRect(x: 0, y: 0, width: 200, height: 200)
        guard let pdf = CGContext(url as CFURL, mediaBox: &box, nil) else {
            return
        }
        for item in array {
            pdf.beginPDFPage(nil)
            let renderer = ImageRenderer(content:
                Text(item)
            )
            renderer.render { size, context in
                context(pdf)
            }
            pdf.endPDFPage()
        }
        pdf.closePDF()
        pdfURL = url
    }
}

This does not show the delay too well but with a more complicated view that takes a while to render the blocking of the UI is significant and the progressView is never shown.

I have tried to use a global queue and dispatch to background but then I can’t draw the view without crashes. I’m wondering what is the best way to render a view to a pdf without blocking the main UI or at least being able to show a progressView while the operation is ongoing.

Latest articles

spot_imgspot_img

Related articles

Leave a reply

Please enter your comment!
Please enter your name here

spot_imgspot_img