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

如何使用UIPrintInteractionController异步打印URL中的PDF文件?

解决iOS打印PDF时主线程阻塞导致UI冻结的问题

问题背景

iOS应用中实现打印送货单功能:点击选项后从服务器获取PDF文件URL,跳转至含打印按钮的页面。前序流程正常,但点击打印按钮后视图冻结,收到如下警告:

主线程上的同步URL加载会导致UI无响应,请改用URLSession等异步API。

现有代码直接将远程URL传入打印控制器,导致同步加载阻塞主线程。

解决方案

核心思路:先通过URLSession异步将PDF文件下载到本地临时目录,再使用本地文件URL进行打印操作,避免主线程阻塞。

1. 新增异步下载PDF的工具函数

import Foundation

func downloadPDF(from url: URL, completion: @escaping (URL?, Error?) -> Void) {
    let task = URLSession.shared.downloadTask(with: url) { localURL, _, error in
        guard let localURL = localURL, error == nil else {
            completion(nil, error)
            return
        }
        // 将临时文件移到稳定的临时目录,避免被系统提前清理
        let fileManager = FileManager.default
        let tempDir = fileManager.temporaryDirectory
        let destinationURL = tempDir.appendingPathComponent("\(UUID().uuidString).pdf")
        
        do {
            if fileManager.fileExists(atPath: destinationURL.path) {
                try fileManager.removeItem(at: destinationURL)
            }
            try fileManager.moveItem(at: localURL, to: destinationURL)
            completion(destinationURL, nil)
        } catch {
            completion(nil, error)
        }
    }
    task.resume()
}

2. 修改打印函数,适配本地文件URL

public enum PrintingResult {
    case success
    case failure(Error)
    case userCancelled
}

public func presentPrintInteractionController(localFileURL: URL?, jobName: String? = nil, completion: ((PrintingResult) -> Void)? = nil) {
    let printController = UIPrintInteractionController()
    let printInfo = UIPrintInfo.printInfo()
    if let jobName = jobName {
        printInfo.jobName = jobName
    }
    printController.printInfo = printInfo
    
    if let localFileURL = localFileURL {
        printController.printingItem = localFileURL
    }
    printController.present(animated: true) { _, completed, error in
        guard let completion = completion else { return }
        if completed {
            completion(.success)
        } else {
            if let error = error {
                completion(.failure(error))
            } else {
                completion(.userCancelled)
            }
        }
    }
}

3. 更新SwiftUI视图,处理异步流程与加载状态

import SwiftUI

struct ReportView: View {
    var reportUrl: String
    @State private var isLoading = false
    
    var body: some View {
        VStack {
            Button {
                guard let url = URL(string: reportUrl), !isLoading else { return }
                isLoading = true
                
                downloadPDF(from: url) { localURL, error in
                    DispatchQueue.main.async {
                        isLoading = false
                        if let localURL = localURL {
                            presentPrintInteractionController(localFileURL: localURL, jobName: "Print a pdf report") { result in
                                switch result {
                                case .success:
                                    print("打印成功")
                                case .failure(let error):
                                    print("错误:\(error)")
                                case .userCancelled:
                                    print("打印任务已取消")
                                }
                            }
                        } else if let error = error {
                            print("下载PDF失败:\(error)")
                        }
                    }
                }
            } label: {
                if isLoading {
                    ProgressView()
                } else {
                    Text("打印")
                }
            }
            .disabled(isLoading)
        }
    }
}

struct ReportView_Previews: PreviewProvider {
    static var previews: some View {
        ReportView(reportUrl: "")
    }
}

关键说明

  • 下载操作通过URLSession.downloadTask在后台线程执行,完全不阻塞主线程
  • 下载完成后将文件移至应用临时目录,确保打印过程中文件不会被系统清理
  • 视图中添加加载状态与按钮禁用逻辑,避免用户重复触发操作
  • 所有UI更新操作切回主线程执行,符合SwiftUI的线程安全要求

内容的提问来源于stack exchange,提问作者Shawkath Srijon

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.27 21:07:08