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.
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;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With