Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Shared UITableViewDelegate

I'm writting a subclass of UITableView and I want my subclass to handle some of the UITableViewDelegate methods itself before passing them along to the "real" delegate as well as forward all the UITableViewDelegate methods not implemented by my subclass.

In the subclass I have a private property:

@property (nonatomic, assign) id <UITableViewDelegate> trueDelegate;

which holds the "real delegate" that all the unimplemented methods should forward to. In both my init methods I set

self.delegate = self;

and I override - (void)setDelegate:(id) like this

-(void)setDelegate:(id<UITableViewDelegate>)delegate {
    if (delegate != self) {
        _trueDelegate = delegate;
    } else {
        [super setDelegate:self];
    }
}

Then I override these to handle the message forwarding

-(NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
    NSMethodSignature *sig;
    sig = [[self.delegate class] instanceMethodSignatureForSelector:aSelector];
    if (sig == nil) {
        sig = [NSMethodSignature signatureWithObjCTypes:"@^v^c"];
    }
    return sig;
}

- (void)forwardInvocation:(NSInvocation *)anInvocation {
    SEL selector = anInvocation.selector;
    if ([self respondsToSelector:selector]) {
        [anInvocation invokeWithTarget:self];
    } else {
        [anInvocation invokeWithTarget:_trueDelegate];
    }
}

The problem is that the unimplemented delegate methods never get called on the tableview, therefore they are not given a chance to be forwarded along to the _trueDelegate object.

I tried checking for them here:

- (BOOL)respondsToSelector:(SEL)aSelector {

}

but that method is never called for the UITableViewDelegate methods although it catches other methods just fine.

like image 945
Lance Avatar asked Jul 13 '12 21:07

Lance


1 Answers

For performance, UITableView checks and remembers which delegate methods are available as soon as the delegate is set. You set the delegate self first, then the trueDelegate. So at the time the delegate is set on the UITableView, trueDelegate is nil, and so -respondsToSelector: on that one always returns NO.

To fix that, set the delegate after trueDelegate is set. Also, you can simplify the forwarding code. Remove all the code you have above except for the property and replace it with:

- (void)setDelegate:(id <UITableViewDelegate>)delegate
{
    if (delegate == self) return;

    self.trueDelegate = delegate;
    [super setDelegate:self];
}

- (BOOL)respondsToSelector:(SEL)aSelector
{
    if ([super respondsToSelector:aSelector]) return YES;

    return [self.trueDelegate respondsToSelector:aSelector];
}

- (id)forwardingTargetForSelector:(SEL)aSelector
{
    return self.trueDelegate;
}
like image 111
Tammo Freese Avatar answered Sep 23 '22 07:09

Tammo Freese