-1

I'm subclassing UITableView and its protocol UITableViewDelegate and its "datasource" UITableDataSource, everything works fine but I haven't find the clean way to forward the methods from "delegate" and "datasource" from UITableView.

I have tried to "play" with respondsToSelector:, forwardingTargetForSelector: and forwardInvocation: methods of NSObject but I didn't get anything.

I'll show you some code about I'm trying:

My CustomTableView.h:

@protocol TableViewCustomDelegate <UITableViewDelegate>

- (void) anyCustomMethodDelegate;

@end

@protocol TableViewCustomDataSource <UITableViewDataSource>

- (NSInteger) anyCustomMethod;

@end


@interface TableViewCustom : UITableView <UITableViewDelegate, UITableViewDataSource>

@property (nonatomic, weak) id<TableViewCustomDelegate> myDelegate;
@property (nonatomic, weak) id<TableViewCustomDataSource> myDataSource;

@end

And this is my TableViewCustom.m:

@implementation TableViewCustom


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


-(id)forwardingTargetForSelector:(SEL)aSelector {
    if ([self.myDelegate respondsToSelector:aSelector]) {
        return self.myDelegate;
    }
    return [super forwardingTargetForSelector:aSelector];
}

...
...

- (void) setMyDelegate:(id<TableViewCustomDelegate>)delegate
{
    [super setDelegate:self];
    _myDelegate = delegate;
}

- (void) setMyDataSource:(id<TableViewCustomDataSource>)dataSource
{
    [super setDataSource:self];
    _myDataSource = dataSource;
}

..
..

// A method from UITableViewDelegate that I would like to avoid
-(UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
    if ([self.delegateDelegate
respondsToSelector:@selector(tableView:viewForHeaderInSection:)]) {
        return [self.myDelegate tableView:tableView
                           viewForHeaderInSection:section];
    }

    return nil;
}

..
..

@end

I would like to avoid conforms methods just to forward it to "myDelegate".

I think it should be work with responsToSelector: and forwardingTargetForSelector: like I do in my code but it doesn't work. I don't know if I'm doing something wrong or if it is not possible.

Thanks in advance.

Regards.

Tulon
  • 3,684
  • 6
  • 31
  • 50
  • You don't have to forward your custom `UITableView` subclass's methods. Just assign your controller as tableview's delegate and datasource and it will work with no additional logic applied. – Eugene May 19 '14 at 19:30
  • You don't ordinarily need to subclass `UITableView`. Is there something in particular you're trying to accomplish? – jlehr May 19 '14 at 19:35
  • Agree UITableView shouldn't be subclassed for delegate/datasource reasons. – malhal Apr 22 '20 at 13:28

3 Answers3

2

I might be misunderstanding your intent, but if you just want your subclass to utilize the standard delegate and datasource, just leave those methods alone and hand the subclass whatever delegate/datasource you want. e.g.

MyTableViewSubclass *tableView = [[MyTableViewSubclass alloc] initWithFrame:....];
tableView.datasource = // anything that implements UITableViewDatasource
tableView.delegate = // anything that implements UITableViewDelegate

Then don't do anything special with those properties or protocols in your subclass.

danh
  • 55,236
  • 10
  • 89
  • 124
  • Danh, you understood ok. I have checked your solution and I think it is more clear and safest. Thanks for you answer. – user1819600 May 20 '14 at 14:11
0

In order to make messaging work, you need to implement following methods:

-(void)forwardInvocation:(NSInvocation *)invocation {
    SEL aSelector = [invocation selector];

    if ([self.myDelegate respondsToSelector:aSelector]) {
        [invocation invokeWithTarget:self.myDelegate];
    }
}

-(NSMethodSignature*)methodSignatureForSelector:(SEL)selector {
    NSMethodSignature *signature = [super methodSignatureForSelector:selector];

    if (nil == signature) {
        signature = [self.myDelegate methodSignatureForSelector:selector];
    }
    return signature;
}
Kyle
  • 16,103
  • 26
  • 123
  • 231
evil159
  • 26
  • 2
  • 6
  • While what you describe would work, I think this is overly complex and not the right solution. Danh's suggestion of setting up the other object as the datasource and/or delegate seems much simpler. – Duncan C May 19 '14 at 20:59
  • Yeap, didn't notice his answer. – evil159 May 19 '14 at 21:07
  • evil159, I tried your solution too before ask here and I didn't get success results. I think Danh's solution is simpler and it is enough for my intention. – user1819600 May 20 '14 at 14:14
-1

Please see the comments lines for explanation

- (void) setMyDelegate:(id<TableViewCustomDelegate>)delegate
{
    //you told you will handle delegate methods to SUPER in our case UITableView

    [super setDelegate:self]; 
    _myDelegate = delegate;   //You have internally stored the delegate 
}

In View For Header

  //You are overriding this method
  //Table View will not handle this as you have overridden.
-(UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
      //You check whether your delegate can do that.
     if ([self.delegateDelegate respondsToSelector:@selector(tableView:viewForHeaderInSection:)]) 
     {
           return [self.myDelegate tableView:tableView
                       viewForHeaderInSection:section];
      }
       //If you delegate is not doing, you need to handle that
       // However returning nil. So Instead of UIView the framework gets nil
       //You need to handle this if your delegate is not handling this
      return nil;
  }
Naveen Prasad R
  • 1,942
  • 1
  • 13
  • 16