There's problem with PDFKit appeared after upd

2020-04-20 03:42发布

问题:

The app crashes when I try to use pdfkit to display pdf-file. Here's the simple example​:

import UIKit
import PDFKit

class ViewController: UIViewController {

    @IBOutlet weak var pdfView: PDFView!

    override func viewDidLoad() {
        super.viewDidLoad()
        if let path = Bundle.main.path(forResource: "file", ofType: "pdf") {
            let url = URL(fileURLWithPath: path)
            if let pdfDocument = PDFDocument(url: url) {
                pdfView.displayMode = .singlePageContinuous
                pdfView.autoScales = true
                // pdfView.displayDirection = .horizontal
                pdfView.document = pdfDocument
            }
        }
    }
}

This crashes with "uncaught exception 'CALayerInvalidGeometry', reason: 'CALayer position contains NaN: [nan nan]'":

2019-03-26 21:09:47.837837+0400 pdfKitTest[3163:93151] libMobileGestalt MobileGestalt.c:890: MGIsDeviceOneOfType is not supported on this platform.
2019-03-26 21:09:47.927078+0400 pdfKitTest[3163:93151] *** Terminating app due to uncaught exception 'CALayerInvalidGeometry', reason: 'CALayer position contains NaN: [nan nan]'
*** First throw call stack:
(
    0   CoreFoundation                      0x000000010e2326fb __exceptionPreprocess + 331
    1   libobjc.A.dylib                     0x000000010c8daac5 objc_exception_throw + 48
    2   CoreFoundation                      0x000000010e232555 +[NSException raise:format:] + 197
    3   QuartzCore                          0x00000001112d52ae _ZN2CA5Layer12set_positionERKNS_4Vec2IdEEb + 140
    4   QuartzCore                          0x00000001112c468b -[CALayer setPosition:] + 57
    5   QuartzCore                          0x00000001112c4de3 -[CALayer setFrame:] + 560
    6   PDFKit                              0x000000010c059097 -[PDFPageLayerTile initWithFrame:forPageLayer:withRenderingTransform:tileContentsScale:generationID:] + 168
    7   PDFKit                              0x000000010c05e805 -[PDFPageLayer _updateTiles] + 3439
    8   PDFKit                              0x000000010c059d8e -[PDFPageLayer setNeedsTilesUpdate] + 87
    9   PDFKit                              0x000000010c06e97d -[PDFPageView setNeedsTilesUpdate] + 48
    10  PDFKit                              0x000000010c070816 -[PDFPageView setFrame:] + 334
    11  PDFKit                              0x000000010c06711c -[PDFDocumentView createPageViewForPageAtIndex:] + 764
    12  PDFKit                              0x000000010c068326 -[PDFDocumentView updateVisibility] + 1726
    13  PDFKit                              0x000000010c0d776f -[PDFView resizeDisplayView:] + 517
    14  PDFKit                              0x000000010c0d0cdf -[PDFView layoutDocumentView] + 464
    15  PDFKit                              0x000000010c0cc36a -[PDFView setDocument:waitDuration:] + 1246
    16  pdfKitTest                          0x000000010bd277e2 $s10pdfKitTest14ViewControllerC11viewDidLoadyyF + 1506
    17  pdfKitTest                          0x000000010bd27924 $s10pdfKitTest14ViewControllerC11viewDidLoadyyFTo + 36
    18  UIKitCore                           0x0000000112fda43b -[UIViewController loadViewIfRequired] + 1183
    19  UIKitCore                           0x0000000112fda868 -[UIViewController view] + 27
    20  UIKitCore                           0x0000000113612c33 -[UIWindow addRootViewControllerViewIfPossible] + 122
    21  UIKitCore                           0x0000000113613327 -[UIWindow _setHidden:forced:] + 289
    22  UIKitCore                           0x0000000113625f86 -[UIWindow makeKeyAndVisible] + 42
    23  UIKitCore                           0x00000001135d5f1c -[UIApplication _callInitializationDelegatesForMainScene:transitionContext:] + 4555
    24  UIKitCore                           0x00000001135db0c6 -[UIApplication _runWithMainScene:transitionContext:completion:] + 1617
    25  UIKitCore                           0x0000000112e206d6 __111-[__UICanvasLifecycleMonitor_Compatability _scheduleFirstCommitForScene:transition:firstActivation:completion:]_block_invoke + 904
    26  UIKitCore                           0x0000000112e28fce +[_UICanvas _enqueuePostSettingUpdateTransactionBlock:] + 153
    27  UIKitCore                           0x0000000112e202ec -[__UICanvasLifecycleMonitor_Compatability _scheduleFirstCommitForScene:transition:firstActivation:completion:] + 236
    28  UIKitCore                           0x0000000112e20c48 -[__UICanvasLifecycleMonitor_Compatability activateEventsOnly:withContext:completion:] + 1091
    29  UIKitCore                           0x0000000112e1efba __82-[_UIApplicationCanvas _transitionLifecycleStateWithTransitionContext:completion:]_block_invoke + 782
    30  UIKitCore                           0x0000000112e1ec71 -[_UIApplicationCanvas _transitionLifecycleStateWithTransitionContext:completion:] + 433
    31  UIKitCore                           0x0000000112e239b6 __125-[_UICanvasLifecycleSettingsDiffAction performActionsForCanvas:withUpdatedScene:settingsDiff:fromSettings:transitionContext:]_block_invoke + 576
    32  UIKitCore                           0x0000000112e24610 _performActionsWithDelayForTransitionContext + 100
    33  UIKitCore                           0x0000000112e2371d -[_UICanvasLifecycleSettingsDiffAction performActionsForCanvas:withUpdatedScene:settingsDiff:fromSettings:transitionContext:] + 223
    34  UIKitCore                           0x0000000112e286d0 -[_UICanvas scene:didUpdateWithDiff:transitionContext:completion:] + 392
    35  UIKitCore                           0x00000001135d99a8 -[UIApplication workspace:didCreateScene:withTransitionContext:completion:] + 514
    36  UIKitCore                           0x0000000113190dfa -[UIApplicationSceneClientAgent scene:didInitializeWithEvent:completion:] + 361
    37  FrontBoardServices                  0x00000001194cd125 -[FBSSceneImpl _didCreateWithTransitionContext:completion:] + 448
    38  FrontBoardServices                  0x00000001194d6ed6 __56-[FBSWorkspace client:handleCreateScene:withCompletion:]_block_invoke_2 + 283
    39  FrontBoardServices                  0x00000001194d6700 __40-[FBSWorkspace _performDelegateCallOut:]_block_invoke + 53
    40  libdispatch.dylib                   0x000000010f5c5db5 _dispatch_client_callout + 8
    41  libdispatch.dylib                   0x000000010f5c92ba _dispatch_block_invoke_direct + 300
    42  FrontBoardServices                  0x0000000119508146 __FBSSERIALQUEUE_IS_CALLING_OUT_TO_A_BLOCK__ + 30
    43  FrontBoardServices                  0x0000000119507dfe -[FBSSerialQueue _performNext] + 451
    44  FrontBoardServices                  0x0000000119508393 -[FBSSerialQueue _performNextFromRunLoopSource] + 42
    45  CoreFoundation                      0x000000010e199be1 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 17
    46  CoreFoundation                      0x000000010e199463 __CFRunLoopDoSources0 + 243
    47  CoreFoundation                      0x000000010e193b1f __CFRunLoopRun + 1231
    48  CoreFoundation                      0x000000010e193302 CFRunLoopRunSpecific + 626
    49  GraphicsServices                    0x00000001166b42fe GSEventRunModal + 65
    50  UIKitCore                           0x00000001135dcba2 UIApplicationMain + 140
    51  pdfKitTest                          0x000000010bd28a7b main + 75
    52  libdyld.dylib                       0x000000010f63a541 start + 1
    53  ???                                 0x0000000000000001 0x0 + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException
(lldb) 

If I comment this line:

 pdfView.document = pdfDocument

the app doesn't crash, but pdf-file also doesn't show, of course. How to fix this problem?

回答1:

I would suggest (just guessing) that maybe viewDidLoad is too early. The view is not yet in the view hierarchy, so there are things you cannot do. The error is complaining that the layer has no position, which makes sense because it has no superlayer.

To confirm that that's the issue, try moving all that code to viewDidAppear. If the crash goes away, we’re on the right track. You can then experiment with moving it into some better event if desired. I would suggest viewDidLayoutSubviews. You will need to make sure the code doesn't run multiple times (using a Bool instance property as a flag).



回答2:

As an alternative I would like to point out that you can also resolve (/hack) this issue by refraining from setting the frame for PDFView before viewDidLayoutSubviews (via: Terminating app due to uncaught exception 'CALayerInvalidGeometry', reason: 'CALayer position contains NaN: [nan nan]'). I'm guessing this delays calls that otherwise lead to the crash.

This is useful when moving the pdfView.document = pdfDocument is cumbersome because for instance the PDFView preparation happens outside of the Viewcontroller. (Personally I would have had to change the entire structure of my program to perform the document setting in viewDidLayoutSubviews).


In short, after changing this:

self.pdfView = PDFView(frame: containerFrame)

to this:

self.pdfView = PDFView()

I could set pdfView.document without crashing the app.



回答3:

For me moving PDFView code from "viewDidLoad" into "viewDidAppear()" did NOT solve the problem! PDFView created in storyboard with a View -> Class: "PDFView".

Moving into "viewDidLayoutSubviews()" (with boolean flag to detect multiple calls) DID resolve this issue.

Also: sample code of PDFKitDemo from Vipul on github from 12/19/17 crashes on my xcode 10.2.1 environment for the same reason, as PDFView handling is in "viewDidLoad" in this sample code as well!

Code snippet working now below:

[...]
var pdfInit : Bool = false

override func viewDidLayoutSubviews() {
  if (!pdfInit) {
    pdfInit = true;

    let documentsUrl:URL = getDocumentsDirectory()
    let pdfFileUrl = documentsUrl.appendingPathComponent("test1.pdf")
    if let myDocument = PDFDocument(url: pdfFileUrl) {
        pdfView.displayMode = .singlePageContinuous
        pdfView.document = myDocument
    }
  }
}

func getDocumentsDirectory() -> URL {
  let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
  let documentsDirectory = paths[0]
  return documentsDirectory
}
[...]