Search code examples
swiftuikitios-pdfkit

How can I properly pass an array in iOS PDFKit


I'm trying to in an [string] array for a PDF. Below is what I have so far. I am guess I need to do a foreach somewhere, but I'm not entirely sure.

I thought something like this might work, but it does not.

       for entry in body {
        let attributedText = NSAttributedString(
            string: entry,
            attributes: textAttributes
        )
    }

private func addBody(body: [String], pageRect: CGRect, textTop: CGFloat) {
    let pageWidth = 8.5 * 72.0
    let pageHeight = 11 * 72.0
    let pageRect = CGRect(x: 0, y: 0, width: pageWidth, height: pageHeight)

    let bodyCG = addInstructor(instructor: "", pageRect: pageRect)
    let textFont = UIFont.systemFont(ofSize: 12.0, weight: .regular)

    let paragraphStyle = NSMutableParagraphStyle()
    paragraphStyle.alignment = .natural
    paragraphStyle.lineBreakMode = .byWordWrapping

    let textAttributes = [
      NSAttributedString.Key.paragraphStyle: paragraphStyle,
      NSAttributedString.Key.font: textFont
    ]

    let attributedText = NSAttributedString(
        string: body,
      attributes: textAttributes
    )

    let textRect = CGRect(
      x: 15,
      y: bodyCG + 30,
      width: pageRect.width - 20,
      height: pageRect.height - textTop - pageRect.height / 5.0
    )
    attributedText.draw(in: textRect)
}

Adding some additional details. If I don't use [String] and just use String everything works fine. The PDF is generated, The concept I'm struggling to understand is how can I pass an array for the PDF.

var courseAttendees : [String] = ["name", "name", "name", "name"]

For Example, I want to pass courseAttendees and then loop through the array the names are just overlapped and shown below.

enter image description here

Final code.

private func addBody(body: [String], textTop: CGFloat) {
        let pageWidth = 8.5 * 72.0
        let pageHeight = 11 * 72.0
        let pageRect = CGRect(x: 0, y: 0, width: pageWidth, height: pageHeight)

        let bodyCG = addInstructor(instructor: "", pageRect: pageRect)
        let textFont = UIFont.systemFont(ofSize: 12.0, weight: .regular)

        let textAttributes: [NSAttributedString.Key: Any] =
          [NSAttributedString.Key.font: textFont]

        // keep track of the y position on the page. You might need
        // to set this globally as you have multiple pages
        var currentYPos: CGFloat = bodyCG

        // Loop through the array
         for entry in body {

             let attributedText = NSAttributedString(
                string: "\(entry)",
               attributes: textAttributes
             )

             // Update the currentYPos
             currentYPos += 15

             // Use the currentYPos in the textRect
             let textRect = CGRect(
               x: 15,
               y: currentYPos,
               width: pageRect.width - 20,
               height: pageRect.height - textTop - pageRect.height / 5.0
             )
             attributedText.draw(in: textRect)
         }
    }

Solution

  • Based on your question and image, I am assuming the PDF creation works fine but the data is not rendered as desired.

    I think the two questions to answer here are:

    1. Where to loop through your array
    2. How to keep track of the current y coordinate in the page which is responsible for the vertical positioning

    Here are some additions I made to try and fix your issue, I have added comments to what I have changed

    // Somewhere appropriate in your code
    var courseAttendees : [String] = ["name1", "name2", "name3", "name4"]
    
    // Call the function, 15 is just a random number for textTop, 
    // give it what you feel is appropriate
    addBody(body: courseAttendees, textTop: 15)
    
    // I have removed the pageRect parameter since you create it
    // in the function
    private func addBody(body: [String], textTop: CGFloat) {
        let pageWidth = 8.5 * 72.0
        let pageHeight = 11 * 72.0
        let pageRect = CGRect(x: 0, y: 0, width: pageWidth, height: pageHeight)
    
        let bodyCG = addInstructor(instructor: "", pageRect: pageRect)
        let textFont = UIFont.systemFont(ofSize: 12.0, weight: .regular)
    
        let paragraphStyle = NSMutableParagraphStyle()
        paragraphStyle.alignment = .natural
        paragraphStyle.lineBreakMode = .byWordWrapping
    
        let textAttributes = [
          NSAttributedString.Key.paragraphStyle: paragraphStyle,
          NSAttributedString.Key.font: textFont
        ]
        
        // keep track of the y position on the page. You might need
        // to set this globally as you have multiple pages
        var currentYPos: CGFloat = 0.0
        
        // Loop through the array
        for entry in body {
            
            let attributedText = NSAttributedString(
                string: entry,
              attributes: textAttributes
            )
            
            // Update the currentYPos
            currentYPos += bodyCG + 30
    
            // Use the currentYPos in the textRect
            let textRect = CGRect(
              x: 15,
              y: currentYPos,
              width: pageRect.width - 20,
              height: pageRect.height - textTop - pageRect.height / 5.0
            )
            attributedText.draw(in: textRect)
        }
    }
    

    I have not tested the above so please give this a try and check if it solves your issue.

    If not, comment and I will update this accordingly.