Skip to content

Instantly share code, notes, and snippets.

@steipete
Created June 4, 2012 22:18
Show Gist options
  • Star 15 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save steipete/2871154 to your computer and use it in GitHub Desktop.
Save steipete/2871154 to your computer and use it in GitHub Desktop.
This was nice and fast... but it takes up WAY TOO MUCH space. And it's annoying to write.
(I like the way I can just step into the function that calls the delegate for debugging)
What's a better way to not make me call respondsToSelector in the middle of my code? Some proxy?
struct {
unsigned int delegateWillDisplayDocument:1;
unsigned int delegateDidDisplayDocument:1;
unsigned int delegateDidShowPageView:1;
unsigned int delegateDidRenderPageView:1;
unsigned int delegateDidChangeViewMode:1;
unsigned int delegateDidTapOnPageView:1;
unsigned int delegateDidTapOnAnnotation:1;
unsigned int delegateShouldDisplayAnnotation:1;
unsigned int delegateViewForAnnotation:1;
unsigned int delegateAnnotationViewForAnnotation:1;
unsigned int delegateWillShowAnnotationView:1;
unsigned int delegateDidShowAnnotationView:1;
unsigned int delegateDidLoadPageView:1;
unsigned int delegateWillUnloadPageView:1;
unsigned int delegateDidEndPageScrollingAnimation:1;
unsigned int delegateDidEndZoomingAtScale:1;
unsigned int delegateWillShowControllerAnimated:1;
unsigned int delegateDidShowControllerAnimated:1;
} delegateFlags_;
- (void)setDelegate:(id<PSPDFViewControllerDelegate>)delegate {
if (delegate != delegate_) {
delegate_ = delegate;
delegateFlags_.delegateWillDisplayDocument = [delegate respondsToSelector:@selector(pdfViewController:willDisplayDocument:)];
delegateFlags_.delegateDidDisplayDocument = [delegate respondsToSelector:@selector(pdfViewController:didDisplayDocument:)];
delegateFlags_.delegateDidShowPageView = [delegate respondsToSelector:@selector(pdfViewController:didShowPageView:)];
delegateFlags_.delegateDidRenderPageView = [delegate respondsToSelector:@selector(pdfViewController:didRenderPageView:)];
delegateFlags_.delegateDidChangeViewMode = [delegate respondsToSelector:@selector(pdfViewController:didChangeViewMode:)];
delegateFlags_.delegateDidTapOnPageView = [delegate respondsToSelector:@selector(pdfViewController:didTapOnPageView:info:coordinates:)];
delegateFlags_.delegateDidTapOnAnnotation = [delegate respondsToSelector:@selector(pdfViewController:didTapOnAnnotation:page:info:coordinates:)];
delegateFlags_.delegateShouldDisplayAnnotation = [delegate respondsToSelector:@selector(pdfViewController:shouldDisplayAnnotation:onPageView:)];
delegateFlags_.delegateViewForAnnotation = [delegate respondsToSelector:@selector(pdfViewController:viewForAnnotation:onPageView:)];
delegateFlags_.delegateAnnotationViewForAnnotation = [delegate respondsToSelector:@selector(pdfViewController:annotationView:forAnnotation:onPageView:)];
delegateFlags_.delegateWillShowAnnotationView = [delegate respondsToSelector:@selector(pdfViewController:willShowAnnotationView:onPageView:)];
delegateFlags_.delegateDidShowAnnotationView = [delegate respondsToSelector:@selector(pdfViewController:didShowAnnotationView:onPageView:)];
delegateFlags_.delegateDidLoadPageView = [delegate respondsToSelector:@selector(pdfViewController:didLoadPageView:)];
delegateFlags_.delegateWillUnloadPageView = [delegate respondsToSelector:@selector(pdfViewController:willUnloadPageView:)];
delegateFlags_.delegateDidEndPageScrollingAnimation = [delegate respondsToSelector:@selector(pdfViewController:didEndPageScrollingAnimation:)];
delegateFlags_.delegateDidEndZoomingAtScale = [delegate respondsToSelector:@selector(pdfViewController:didEndPageZooming:atScale:)];
delegateFlags_.delegateWillShowControllerAnimated = [delegate respondsToSelector:@selector(pdfViewController:willShowController:embeddedInController:animated:)];
delegateFlags_.delegateDidShowControllerAnimated = [delegate respondsToSelector:@selector(pdfViewController:didShowController:embeddedInController:animated:)];
}
}
- (void)delegateWillDisplayDocument {
if (delegateFlags_.delegateWillDisplayDocument) {
[self.delegate pdfViewController:self willDisplayDocument:self.document];
}
}
- (void)delegateDidDisplayDocument {
if(delegateFlags_.delegateDidDisplayDocument) {
[self.delegate pdfViewController:self didDisplayDocument:self.document];
}
}
(etc, etc)
@jonsterling
Copy link

  1. Like I said, you can't use -forwardingTargetForSelector:, because if nothing happens there, the runtime will try -forwardInvocation:.
  2. The compound literal is so that you can build the struct in one pass, without having to set all of its values individually. So, the following are equivalent:
// this is retarded:
point.x = 1.f;
point.y = 3.f;

// this is awesome:
point = (CGPoint) { .x = 1.f, .y = 3.f };

@Daij-Djan
Copy link

a macro or a simple function or method would look good and could even use the caching (don't know If Id want that though)...

anyways :) id be interested in hearing what you finally decide on

@macguru
Copy link

macguru commented Jun 5, 2012

I prefer to check the respondsToSelector in place. Generally rather dislike such caches. I usually don't have that much delegate methods though...

However, you could build a proxy class that assembles method implementations automatically using runtime calls. That'd be extremely elegant, albeit a bit of work and probably shooting with canons on pigeons. You could open-source it afterwards though ;)

@hatfinch
Copy link

hatfinch commented Aug 1, 2012

No proxy tricks, but FWIW I use ids directly:

struct
{
    id willDisplayDocumentDelegate;
    id didDisplayDocumentDelegate;
    // etc.
} _delegates;

- (void)setDelegate:(id <PSPDFViewControllerDelegate>)delegate
{
    if (delegate)
    {
        if ([delegate respondsToSelector:@selector(pdfViewController:willDisplayDocument:)])
            _delegates.willDisplayDocumentDelegate = delegate;

        if ([delegate respondsToSelector:@selector(pdfViewController:didDisplayDocument:)])
            _delegates.didDisplayDocumentDelegate = delegate;

        // etc.
    }
    else
        memset(_delegates, 0, sizeof(_delegates));
}

- (void)delegateWillDisplayDocument
{
    [_delegates.willDisplayDocumentDelegate pdfViewController:self willDisplayDocument:self.document];
}

- (void)delegateDidDisplayDocument
{
    [delegates_.didDisplayDocumentDelegate pdfViewController:self didDisplayDocument:self.document];
}

// etc.

@MichaelHackett
Copy link

I like your approach, @hatfinch, but should the zeroing of the _delegates table not should happen first, and unconditionally, as the if statements only set the fields for methods that are present in the new delegate. If there was a previous setting for a field and the new delegate doesn't implement that method, the old value would still be present (causing the old delegate to be called for some methods).

Also, I believe that object refs in a struct are no longer allowed under ARC, but (__weak) ivars could work just as well.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment