Overriding Classes in Our iOS Viewer

PSPDFKit has a unique and easy-to-use system that allows you to subclass classes that are used deeply within the framework without having to know where they’re all instantiated.

The PDFConfigurationBuilder(opens in a new tab) object has an overrideClass(_:with:)(opens in a new tab) method in the builder, which is where you can register your subclasses to be used in place of the default PSPDFKit classes.

Let’s say you want to move the ScrubberBar(opens in a new tab) all the way to the top. Classes usually don’t manage their placement themselves, so in this example, the class is managed by the UserInterfaceView(opens in a new tab), which requires you to override the class. We usually expose a variety of hooks that are meant to be modified in a subclass:

extension UserInterfaceView {
/// Update these to manually set the frame.
open func updateDocumentLabelFrame(animated: Bool)
open func updatePageLabelFrame(animated: Bool)
open func updateThumbnailBarFrame(animated: Bool)
open func updateScrubberBarFrame(animated: Bool)
}

Here we’re interested in modifying the updateScrubberBarFrame(animated:)(opens in a new tab) method.

First, we create a custom subclass where we override this method:

class CustomUserInterfaceView: UserInterfaceView {
override func updateScrubberBarFrame(animated: Bool) {
super.updateScrubberBarFrame(animated: animated)
// Stick scrubber bar to the top.
var newFrame = dataSource!.contentRect
newFrame.size.height = 44
scrubberBar.frame = newFrame
}
}

Next, we register our custom subclass:

let pdfController = PDFViewController(document: document) {
$0.overrideClass(UserInterfaceView.self, with: CustomUserInterfaceView.self)
}

That’s it! From now on, every time PSPDFKit creates a UserInterfaceView(opens in a new tab), it actually uses CustomUserInterfaceView.

Things to Keep in Mind

  • Your subclass must be an actual subclass or we’ll throw an exception to warn you.
  • Only classes that already conform to the Overridable(opens in a new tab) protocol can be overridden. Don’t add conformance to this protocol for any other existing classes or for your new ones.
  • Most methods require that you call them on super.
  • Model-related classes need to be registered in Document(opens in a new tab)’s overrideClass(_:with:)(opens in a new tab).
  • Overrides need to be registered before calling any other method on the object (e.g. trying to set an override on the document after unlock(withPassword:)(opens in a new tab) has been called will silently fail — it’d be too expensive to check all calls for timing correctness).
  • If you see a getter/setter property pair or a read-only getter, don’t override it unless doing so is specifically documented. In most cases, this will lead to unexpected/inconsistent/buggy behavior. PSPDFKit will even detect and assert some of these attempts, but we can’t possibly anticipate every use and every way to dynamically override properties. In most cases, there will be a better way to achieve what you’re trying to do — ping us on support; we’re happy to help.
OSZAR »