Overriding Classes


PSPDFKit has a quite unique and comfortable system that allows you to subclass classes that are used deeply within the framework, without having to know where they are all instantiated.

The PSPDFConfiguration object has a overrideClass:withClass: method in the builder, where you can register your subclasses to be used instead of the vanilla PSPDF objects.

Let's say you want to move the PSPDFScrubberBar all the way to the top. Classes usually don't manage their placement themselves. This class is managed by the PSPDFHUDView, so you need to override this class. We often expose a variety of hooks that are intended to be modified in a subclass:

Copy
1
2
3
4
5
6
7
8
extension PSPDFHUDView {

    /// 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)
}
Copy
1
2
3
4
5
6
7
8
@interface PSPDFHUDView (SubclassingHooks)

// Update these to manually set the frame.
- (void)updateDocumentLabelFrameAnimated:(BOOL)animated;
- (void)updatePageLabelFrameAnimated:(BOOL)animated;
- (void)updateThumbnailBarFrameAnimated:(BOOL)animated;
- (void)updateScrubberBarFrameAnimated:(BOOL)animated;
@end

Here we're interested in modifying the updateScrubberBarFrameAnimated: method.

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

Copy
1
2
3
4
5
6
7
8
9
10
11
class PSCCustomHUDView: PSPDFHUDView {

    override func updateScrubberBarFrame(animated: Bool) {
        super.updateScrubberBarFrame(animated: animated)

        // Stick scrubber bar to the top.
        guard var newFrame = dataSource?.contentRect else { return }
        newFrame.size.height = 44
        scrubberBar.frame = newFrame
    }
}
Copy
1
2
3
4
5
6
7
8
9
10
11
12
13
@interface PSCCustomHUDView : PSPDFHUDView @end
@implementation PSCCustomHUDView

- (void)updateScrubberBarFrameAnimated:(BOOL)animated {
    [super updateScrubberBarFrameAnimated:animated];

    // Stick scrubber bar to the top.
    CGRect newFrame = self.dataSource.contentRect;
    newFrame.size.height = 44.f;
    self.scrubberBar.frame = newFrame;
}

@end

Next, we register our custom subclass:

Copy
1
2
3
let pdfController = PSPDFViewController(document: document, configuration: PSPDFConfiguration { builder in
    builder.overrideClass(PSPDFHUDView.self, with: PSCCustomHUDView.self)
})
Copy
1
2
3
PSPDFViewController *pdfController = [[PSPDFViewController alloc] initWithDocument:document configuration:[PSPDFConfiguration configurationWithBuilder:^(PSPDFConfigurationBuilder *builder) {
    [builder overrideClass:PSPDFHUDView.class withClass:PSCCustomHUDView.class];
}]];

That's it! From now on, every time PSPDFKit creates a PSPDFHUDView, it actually uses PSCCustomHUDView.

Things to keep in mind

  • Your subclass must be an actual subclass, or we'll throw an exception to warn you.
  • Most methods require that you call super on them.
  • Model-related classes need to be registered in PSPDFDocument's overrideClass:withClass:.
  • Overrides need to be registered before calling any other method on the object. (e.g. trying to set an override on the document after unlockWithPassword: has been called will fail silently - it would be too expensive to check all calls for timing correctness.)
  • If you see a getter/setter property pair or a readonly getter, unless specifically documented, do not override it. 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.
Was this page helpful? We're happy to answer any questions.