Контроллер печати iOS использует async в renderer.numberOfPages - PullRequest
0 голосов
/ 29 марта 2019

В настоящее время я использую функцию прямой печати в своем приложении с UIPrintInteractionController.print(to: printer), и мне приходится асинхронно форматировать документ перед отправкой его на принтер с использованием данных UIPrinterPageRenderer.paperRect.

Но это значение доступно только во время print выполнения метода.

У меня есть пользовательская реализация UIPrinterPageRenderer, которая переопределяет numberOfPages метод получения (этот метод вызывается внутри метода print и дает инициализированное значение paperRect).

Так что я могу отформатировать свой документ в этом геттере, но я должен отформатировать свой документ асинхронно, и я застрял здесь ...

Вот мой текущий код:

public class PrintManager : UIPrintInteractionControllerDelegate {
    private var channel: FlutterMethodChannel?
    private var renderer: CustomPrintPageRenderer?

    // Some other methods...

    // Print method called after user interaction
    func print(_ name: String, withPrinter printer: UIPrinter) {
        let controller = UIPrintInteractionController.shared
        controller.delegate = self

        let printInfo = UIPrintInfo.printInfo()
        printInfo.jobName = name
        printInfo.outputType = .general
        controller.printInfo = printInfo

        renderer = CustomPrintPageRenderer(channel)
        controller.renderer = renderer

        controller.print(to: printer, completionHandler: completionHandler)
    }

    // Print completion handler
    func completionHandler(printController _: UIPrintInteractionController, completed: Bool, error: Error?) {
        if !completed, error != nil {
            print("Unable to print", error?.localizedDescription ?? "unknown error")
        }
        renderer = nil
    }
}
class CustomPrintPageRenderer : UIPrintPageRenderer {
    private var channel: FlutterMethodChannel?
    private var pdfDocument: CGPDFDocument?

    init(_ channel: FlutterMethodChannel?) {
        super.init()
        self.channel = channel
        pdfDocument = nil
    }

    // Parse pdfDocument data
    func setDocument(_ data: Data?) {
        let bytesPointer = UnsafeMutablePointer<UInt8>.allocate(capacity: data?.count ?? 0)
        data?.copyBytes(to: bytesPointer, count: data?.count ?? 0)
        let dataProvider = CGDataProvider(dataInfo: nil, data: bytesPointer, size: data?.count ?? 0, releaseData: dataProviderReleaseDataCallback)
        pdfDocument = CGPDFDocument(dataProvider!)
    }

    // This method is called by the UIPrintInteractionController
    override func drawPage(at pageIndex: Int, in _: CGRect) {
        let ctx = UIGraphicsGetCurrentContext()
        let page = pdfDocument?.page(at: pageIndex + 1)
        ctx?.scaleBy(x: 1.0, y: -1.0)
        ctx?.translateBy(x: 0.0, y: -paperRect.size.height)
        ctx?.drawPDFPage(page!)
    }   

    // This getter is called by the UIPrintInteractionController
    override var numberOfPages: Int {
        let formatData = [
            "width": NSNumber(value: Double(paperRect.size.width)),
            "height": NSNumber(value: Double(paperRect.size.height)),
            //...
        ];

        // This method is asynchronous and call a completion handler when it finishes
        channel?.invokeMethod("getDocument", arguments: formatData) {(data: Any?) in 
            // In this completion handler I have my document data
            if let object = data as? FlutterStandardTypedData {
                self.setDocument(object.data)
            }
        }

        // pdfDocument must be initialized here
        let pages = pdfDocument?.nuberOfPages ?? 0

        return pages
    }
}

На самом деле этот код не работает, потому что pdfDocument инициализируется слишком поздно.

Итак, мой вопрос: Есть ли способ ожидания вызова обработчика завершения channel?.invokeMethod()?

Я пытался использовать DispatchSemaphore, но поскольку печать выполняется в основном потоке, она заканчивается заморозкой (и мой обработчик завершения не вызывается).

После некоторых тестов кажется, что controller.print() нельзя вызвать вне основного потока.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...