如何下载并预览API返回的Base64字符串格式PDF文件
Got it, let's walk through this step by step—this is a super common iOS workflow, so I'll make sure each part is clear and actionable.
1. 定义数据模型(可选但推荐)
First off, let's create a simple model to wrap the API response data. This makes handling the array way cleaner than dealing with raw dictionaries every time:
struct PDFItem: Codable { let pdf: String // 对应API返回的Base64字符串 }
When you get the API response, just decode the JSON array into [PDFItem] using JSONDecoder—easy peasy.
2. 配置UITableViewCell与按钮绑定
Next up, set up your UITableViewCell with a UIButton. Instead of using tags (which can get messy if your table updates), use a closure to pass the corresponding PDF data directly when the button is tapped.
First, update your custom cell class:
class PDFTableCell: UITableViewCell { // 假设你的按钮已经在Storyboard/XIB中关联好 @IBOutlet weak var previewSaveButton: UIButton! // 定义闭包来传递点击事件和对应的Base64字符串 var onButtonTap: ((String) -> Void)? @IBAction func buttonTapped(_ sender: UIButton) { guard let cell = sender.superview?.superview as? PDFTableCell, let tapAction = cell.onButtonTap, let pdfItem = cell.pdfItem else { return } tapAction(pdfItem.pdf) } // 存储当前cell对应的PDF数据 var pdfItem: PDFItem? }
Then in your cellForRowAt method, bind the data and closure:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "PDFTableCell", for: indexPath) as! PDFTableCell let pdfItem = pdfItems[indexPath.row] cell.pdfItem = pdfItem // 绑定闭包,把当前的Base64字符串传出去 cell.onButtonTap = { [weak self] base64String in self?.handlePDFAction(base64String: base64String) } return cell }
This way, you don't have to mess with tags or index paths later—super safe, especially if your table has dynamic updates.
3. 核心逻辑:解码、保存与预览
Now for the main event—let's write the handlePDFAction function that does all the heavy lifting:
3.1 解码Base64字符串为Data
First, we need to convert the Base64 string into a Data object. Remember to handle cases where the string might be invalid:
private func handlePDFAction(base64String: String) { // 解码Base64字符串(注意有些API返回的Base64可能带有前缀,需提前移除) let cleanedBase64 = base64String.replacingOccurrences(of: "^data:application/pdf;base64,", with: "", options: .regularExpression) guard let pdfData = Data(base64Encoded: cleanedBase64) else { showError(message: "Failed to decode PDF data") return } // 保存到本地并预览 saveAndPreviewPDF(data: pdfData) }
3.2 保存PDF到本地Documents目录
Next, save the data to your app's private Documents directory. We'll use a unique filename (like a UUID) to avoid overwriting existing files:
private func saveAndPreviewPDF(data: Data) { // 获取Documents目录路径 guard let documentsDir = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first else { showError(message: "Could not access Documents directory") return } // 生成唯一文件名 let fileName = "\(UUID().uuidString).pdf" let fileURL = documentsDir.appendingPathComponent(fileName) // 写入文件 do { try data.write(to: fileURL) // 保存成功,开始预览 previewPDF(at: fileURL) } catch { showError(message: "Failed to save PDF: \(error.localizedDescription)") } }
3.3 使用UIDocumentInteractionController预览PDF
Finally, set up the UIDocumentInteractionController to preview the saved PDF. Don't forget to set its delegate—this is crucial for proper presentation:
// 声明一个属性来持有控制器,避免被提前释放 private var documentController: UIDocumentInteractionController? private func previewPDF(at fileURL: URL) { documentController = UIDocumentInteractionController(url: fileURL) documentController?.delegate = self // 以弹窗形式预览(也可以用presentPreview方法,根据你的需求调整) if let previewController = documentController?.previewViewController { present(previewController, animated: true) } else { showError(message: "Could not open PDF preview") } } // 实现UIDocumentInteractionControllerDelegate的必要方法 extension YourViewController: UIDocumentInteractionControllerDelegate { func documentInteractionControllerViewControllerForPreview(_ controller: UIDocumentInteractionController) -> UIViewController { return self } }
4. 辅助方法:显示错误提示
Add a simple helper to show error alerts to the user:
private func showError(message: String) { let alert = UIAlertController(title: "Error", message: message, preferredStyle: .alert) alert.addAction(UIAlertAction(title: "OK", style: .default)) present(alert, animated: true) }
注意事项
- 内存管理: For large PDFs, make sure you're not holding onto the
Dataobject longer than needed. Using[weak self]in closures helps prevent retain cycles. - Base64前缀处理: Some APIs return Base64 strings with a
data:application/pdf;base64,prefix—don't forget to clean that up before decoding. - 文件名唯一性: Using UUID ensures you don't overwrite existing PDFs—perfect if your users might save multiple files.
- 权限: The Documents directory is private to your app, so you don't need extra privacy permissions to save or access files here.
内容的提问来源于stack exchange,提问作者roshan.k

