Search code examples
iosswiftxcodeios-simulatornsfilemanager

renderer.writePDF doesn't work without error


I learn swift and faced with problem: when i try write pdf file in document directory nothing happened. Code:

func createPDF() {
        // MARK: - create path
        let documentDir = FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask).first!
        let path = documentDir.appendingPathComponent("\(clientCompanyName + UUID().uuidString).pdf")

        // MARK: - create meta
        let pdfMetaData = [
            kCGPDFContextCreator: "something",
            kCGPDFContextAuthor: "https://bla-bla.com"
        ]
        let format = UIGraphicsPDFRendererFormat()
        format.documentInfo = pdfMetaData as [String: Any]
        
        // MARK: - set page size
        let pageWidth = 8.5 * 72.0
        let pageHeight = 11 * 72.0
        let pageRect = CGRect(x: 0, y: 0, width: pageWidth, height: pageHeight)
        
        // MARK: - render
        let renderer = UIGraphicsPDFRenderer(bounds: pageRect, format: format)
        try? renderer.writePDF(to: path) { (context) in
            let attributes = [
                NSAttributedString.Key.font: UIFont.boldSystemFont(ofSize: 72)
            ]
            let text = clientCompanyName + " " + formattedDate
            text.draw(at: CGPoint(x: 0, y: 0), withAttributes: attributes)
        }
    }

When i start this code, i don't see any errors in terminal. But if i open Files, my document didn't save


Solution

  • So I think the problem was that you were not allowed to write to the cachesDirectory. So replace everything with that, it should work. Also with with pageDatas you are now able to print in CGRects on multiple pages, just append the array, you're welcome :)

        func createPDF() -> URL {
                // MARK: - create path
            let documentDir = FileManager.default.temporaryDirectory
                let path = documentDir.appendingPathComponent("\("clientCompanyName" + UUID().uuidString).pdf")
            
                // MARK: - create meta
                let pdfMetaData = [
                    kCGPDFContextCreator: "something",
                    kCGPDFContextAuthor: "https://bla-bla.com"
                ]
            let format = UIGraphicsPDFRendererFormat()
            format.documentInfo = pdfMetaData as [String: Any]
            
            // MARK: - set page size
            let pageWidth = 8.5 * 72.0
            let pageHeight = 11 * 72.0
            let pageRect = CGRect(x: 0, y: 0, width: pageWidth, height: pageHeight)
            
            // MARK: - render
            let renderer = UIGraphicsPDFRenderer(bounds: pageRect, format: format)
            let attributes = [
                    NSAttributedString.Key.font: UIFont.boldSystemFont(ofSize: 72)
                ]
            let text = "clientCompanyName" + " " + "formattedDate"
            let myAttributedString = NSAttributedString(string: text, attributes: attributes)
            let pageDatas = [[[pageRect, myAttributedString]]]
            let pdfData = createCustomPdfDataa(renderer: renderer, pageDatas: pageDatas)
            do {
                try pdfData.write(to: path)
            } catch {
                fatalError("Sorry this does not work, because \(error)")
            }
            return path
        }
    
        func createCustomPdfDataa(renderer: UIGraphicsPDFRenderer, pageDatas: [[[Any?]]]) -> Data {
            // render context to pdfData
            let data = renderer.pdfData { (context) in
                // create pages
                for pageNumber in 0..<pageDatas.count {
                    context.beginPage()
                    let pageData = pageDatas[pageNumber]
                    for textIndex in 0..<pageData.count {
                        drawAttributedText(inFrame: pageData[textIndex][0] as! CGRect, pageData[textIndex][1] as! NSAttributedString)
                    }
                }
            }
            return data
        }
    
    
        func drawAttributedText(inFrame: CGRect, _ text: NSAttributedString) {
            text.draw(in: inFrame)
        }
    }
    

    The createPDF function returns the url you are saving to, so call it with this code below if you want to display it in a PDFView:

        let documentDir = createPDF()
        let data = readDataFromUrl(with: documentDir)
        pdfView.document = PDFDocument(data: data)
    
    
    func readDataFromUrl(with url: URL) -> Data {
        // PathUrl
        let fileURL = url
        // Read
        var readData = Data()
        do {
            readData = try Data(contentsOf: fileURL)
        } catch let jsonErr {
            print("Error read file:", jsonErr)
        }
        return readData
    }