Как узнать, когда PDF отображается с помощью PDFKit

#swift #pdfkit

#swift #pdfkit

Вопрос:

Я пытаюсь показать загрузку, пока PDF-файл еще не был показан на экране. Проблема в том, что моя загрузка всегда останавливается до того, как документ уже отрисован, иногда это не может занять 2 или 3 секунды, и мне нужно знать, когда PDF уже отрисован, чтобы остановить activyIndicator . Возможно ЛИ ЭТО с помощью PDFKIT? Мой код:

 class PDFViewController: URLSessionDownloadDelegate {

    @IBOutlet weak var pdfView: PDFView!
    var pdfDocument: PDFDocument!

    override func viewDidLoad() {
        super.viewDidLoad()

        setupPDFView()
        setupNavigationBar()
    }

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)

        self.startLoading()
    }

    override func viewDidAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        loadPDF()
    }

    private func loadPDF() {
        DispatchQueue.main.async {
            guard let url = URL(string: self.viewModel.pdfURL) else {
                self.showAlert(with: self.viewModel.strings.invalidInvoice)
                return
            }

            let urlSession = URLSession(configuration: .default, delegate: self, delegateQueue: OperationQueue())

            let downloadTask = urlSession.downloadTask(with: url)
            downloadTask.resume()
        }
    }

    private func setupPDFView() {
        self.pdfView.displayMode = .singlePageContinuous
        self.pdfView.autoScales = true
    }

    func startLoading() {

        guard let window = UIApplication.shared.keyWindow,
            !window.subviews.contains(where: { $0 is LoadingView }) else { return }

        let loadingView = LoadingView(frame: window.bounds)
        window.addSubview(loadingView)

        Thread.performUIUpdate {
            loadingView.startAnimation()
        }
    }

    func stopLoading() {

        guard let window = UIApplication.shared.keyWindow,
        let view = window.subviews.first(where: { $0 is LoadingView }),
        let loadingView = view as? LoadingView  else { return }

        Thread.performUIUpdate {
            loadingView.stopAnimation()
            loadingView.removeFromSuperview()
        }
    }

    func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL) {
        DispatchQueue.main.async {
            self.pdfDocument = PDFDocument(url: location)

            if let pdfDocument = self.pdfDocument {
                self.pdfView.document = pdfDocument
            }

            self?.stopLoading()
        }
    }
}
  

Комментарии:

1. Пожалуйста, не публикуйте неполный код. Если self.startLoading() это уместно, покажите определение startLoading . Не оставляйте нас гадать, что он делает.

2. мой плохой. Я только что добавил код

3. Хорошо, я понимаю. Итак, где именно задержка в 2 или 3 секунды? (Я немного удивлен, что ваш код вообще работает, потому что вы недостаточно быстро загружаете загруженный документ, но это может быть другой проблемой.)

4. прямо сейчас я использую URLSession, чтобы остановить LoadingView. Когда я вызываю self?.stopLoading, PDF-файл уже загружен, и PDFView.document уже установлен. Но я вызываю stopLoading, загрузка останавливается… и pdf еще не отображается на экране. Иногда для фактического отображения требуется 2 или 3 секунды, иногда он отображается точно при вызове stopLoading . Кстати, я забыл добавить определение остановки загрузки, я добавляю, но это в основном останавливает просмотр загрузки.

Ответ №1:

Это кажется действительно плохой идеей:

 func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL) {
    DispatchQueue.main.async {
        self.pdfDocument = PDFDocument(url: location)
  

Проблема в том, что, когда вы выходите из текущего потока и запускается асинхронный код, метод завершается, и временный документ at location может быть уничтожен. Я бы предложил написать так:

 func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL) {
    let pdf = PDFDocument(url: location)
    DispatchQueue.main.async {
        self.pdfDocument = pdf
  

Я не говорю, что это решит вашу проблему, но это кажется намного менее опасным, чем то, что вы делаете.

Что касается вашей реальной проблемы, я бы предложил зарегистрироваться для получения уведомления, подобного этому, и посмотреть, придет ли оно в нужный момент.

Ответ №2:

Вы должны наблюдать за уведомлением PDFViewVisiblePagesChanged, чтобы узнать, когда страницы PDFView видны, добавьте свой код в метод.

 NotificationCenter.default.addObserver(self, selector: #selector(pdfViewVisiblePagesChanged(sender:)), name: .PDFViewVisiblePagesChanged, object: nil)

@objc func pdfViewVisiblePagesChanged(sender: Notification) {

    //Add your code here
}