swift 如何使用UIPrintInteractionController从URL异步打印PDF文件?

xuo3flqw  于 2023-03-22  发布在  Swift
关注(0)|答案(1)|浏览(363)

在我的应用程序中,我有一个打印送货单的选项。当我点击这个选项时,我会收到一个带有URL的服务器响应(PDF文件的URL)。收到响应后,应用程序会立即导航到一个屏幕,其中包含一个执行打印操作的按钮。在此之前,一切正常。但当我点击打印按钮时,视图冻结。我收到警告,这是一个同步的URL加载,导致应用程序的UI无响应。它建议使用一些异步URL加载,如URLSession。但我不知道如何在这种情况下使用它。任何帮助都将不胜感激。我提供了下面的代码示例。

  1. public enum PrintingResult {
  2. case success
  3. case failure(Error)
  4. case userCancelled
  5. }
  6. public func presentPrintInteractionController(url: URL?, jobName: String? = nil, completion: ((PrintingResult) -> Void)? = nil) {
  7. let printController = UIPrintInteractionController()
  8. let printInfo = UIPrintInfo.printInfo()
  9. if let jobName = jobName {
  10. printInfo.jobName = jobName
  11. }
  12. printController.printInfo = printInfo
  13. if let url = url {
  14. printController.printingItem = url
  15. }
  16. printController.present(animated: true) { _, completed, error in
  17. guard let completion = completion else { return }
  18. if completed {
  19. completion(.success)
  20. } else {
  21. if let error = error {
  22. completion(.failure(error))
  23. } else {
  24. completion(.userCancelled)
  25. }
  26. }
  27. }
  28. }

查看:

  1. import SwiftUI
  2. struct ReportView: View {
  3. var reportUrl: String
  4. init(reportUrl: String) {
  5. self.reportUrl = reportUrl
  6. }
  7. var body: some View {
  8. VStack {
  9. Button {
  10. presentPrintInteractionController(url: URL(string: reportUrl), jobName: "Print a pdf report") { result in
  11. switch result {
  12. case .success:
  13. print("Print Successful")
  14. case .failure(let error):
  15. print("Error: \(error)")
  16. case .userCancelled:
  17. print("Printing job cancelled.")
  18. }
  19. }
  20. } label: {
  21. Text("Print")
  22. }
  23. }
  24. }
  25. }
  26. struct ReportView_Previews: PreviewProvider {
  27. static var previews: some View {
  28. ReportView(reportUrl: "")
  29. }
  30. }

bpsygsoo

bpsygsoo1#

似乎UIPrintInteractionController正在尝试从远程URL同步获取数据。解决这个问题的一种方法是异步获取数据 * 自己 *,并将Data交给UIPrintInteractionController
其基本思想是:

  1. URLSession.shared.dataTask(with: URLRequest(url: url)) { data, response, error in
  2. // do some error handling...
  3. printController.printingItem = data
  4. printController.present(animated: true) { _, completed, error in
  5. // call your completion handler here...
  6. }
  7. }.resume()

我建议将presentPrintInteractionController转换为async throws函数,并去掉完成处理程序参数。
这种嵌套方式要少得多。

  1. // you don't need to wrap the built-in errors that can be thrown
  2. // so the only case left is userCancelled.
  3. // perhaps consider renaming this
  4. public enum PrintingResult: Error {
  5. case userCancelled
  6. }
  7. // assuming this is a global function, you'd need @MainActor
  8. @MainActor
  9. public func presentPrintInteractionController(url: URL?, jobName: String? = nil) async throws {
  10. let printController = UIPrintInteractionController()
  11. let printInfo = UIPrintInfo.printInfo()
  12. if let jobName = jobName {
  13. printInfo.jobName = jobName
  14. }
  15. printController.printInfo = printInfo
  16. if let url = url {
  17. // fetching the data asynchronously
  18. let (data, response) = try await URLSession.shared.data(from: url)
  19. // you might add some error handling here by inspecting response
  20. printController.printingItem = data
  21. }
  22. try await withCheckedThrowingContinuation { continuation in
  23. printController.present(animated: true) { _, completed, error in
  24. if completed {
  25. continuation.resume()
  26. } else if let e = error {
  27. continuation.resume(with: .failure(e))
  28. } else {
  29. continuation.resume(with: .failure(PrintingResult.userCancelled))
  30. }
  31. }
  32. }
  33. }

然后,您可以在Button代码中使用do...catch来处理以下三种情况:

  1. Button {
  2. Task {
  3. do {
  4. try await presentPrintInteractionController(url: URL(string: reportUrl), jobName: "Print a pdf report")
  5. print("Print Successful")
  6. } catch PrintingResult.userCancelled {
  7. print("Printing job cancelled.")
  8. } catch {
  9. print("Error: \(error)")
  10. }
  11. }
  12. } label: {
  13. Text("Print")
  14. }
展开查看全部

相关问题