You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何下载并预览API返回的Base64字符串格式PDF文件

解决方案:处理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 Data object 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 08:09:53