Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I subclass a UITableView?

I want to subclass a UITableView as I want to create a reusable table view component in my application.

The idea is instead of using a delegate for say cellForRowAtIndexPath I want the table view itself to get that call.

I don't think I want a UITableViewController as this UITableView that I want to build has to live in various UIViewControllers (and these UIViewController might have UITableViews of their own).

I subclassed my UITableView as:

@interface ShareUITableView : UITableView

but none of its methods get called.

My ShareUITableView is created via the NIB by setting the custom class to ShareUITableView. I have verified in code that a ShareUITableView is instantiated.

My UITableView does not delegate to its view controller, so that's not the problem.

Any ideas?

like image 890
pbx Avatar asked Feb 04 '12 20:02

pbx


3 Answers

If I understood you, you need this class declaration:

@interface ShareUITableView : UITableView <UITableViewDataSource>

And then, in your class constructor, you should assign the instance itself as its own datasource:

- (id)init
{
    //...
    self.dataSource = self;
    //...
}

Of course, the class will have to adopt the protocol.

Good luck!

like image 172
Ricard Pérez del Campo Avatar answered Oct 14 '22 05:10

Ricard Pérez del Campo


MyTableView.h

// MyTableView.h

// This overrides the UITableViewDataSource with your own so you can add any methods   you would like.
@protocol MyTableViewDataSource <UITableViewDataSource>

@required
// This is where you put methods that are required for your custom table to work (optional)
- (int)myRequiredMethod;

@optional
// This is where you put methods that are optional, like settings (optional)

@end

// This overrides the UITableViewDelegate with your own so you can add any methods you would like.
@protocol MyTableViewDelegate <UITableViewDelegate>

@required
// This is where you put methods that are required for your custom table to work (optional)

@optional
// This is where you put methods that are optional, like settings (optional)

@end

// Make sure you add UITableViewDelegate and UITableViewDataSource implementations.
@interface MyTableView : UITableView <UITableViewDelegate, UITableViewDataSource> {

    // Your customer datasource and delegate.
    id <MyTableViewDataSource> myDataSource;
    id <MyTableViewDelegate> myDelegate;
}

@end

MyTableView.m

// MyTableView.m

#import "MyTableView.h"

@implementation MyTableView

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        // Initialization code

        // This is how you can use your custom method.
        int i = [myDataSource myRequiredMethod];
    }
    return self;
}

- (void)awakeFromNib {
    // This assigns the delegate and datasource you assigned to File's Owner in your xib to your custom methods
    myDataSource = (id<MyTableViewDataSource>)self.dataSource;
    myDelegate = (id<MyTableViewDelegate>)self.delegate;
    self.delegate = self;
    self.dataSource = self;
}

// This is an example of how to override an existing UITableView method.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {

    // This calls the method implemented in your ViewController. See Below.
    NSInteger rows = [myDataSource tableView:tableView numberOfRowsInSection:section];

    return rows;
}

@end

MyViewController.h

// MyViewController.h

#import "MyTableView.h"

// Use MyTableViewDataSource and MyTableViewDelegate instead of UITableViewDataSource and UITableViewDelegate
@interface MyViewController : UIViewController <MyTableViewDataSource, MyTableViewDelegate> {

@end

MyViewController.m

// MyViewController.m

#import "MyViewController.h"

@interface MyViewController ()

@end

@implementation MyViewController

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) {
        // Custom initialization
    }
    return self;
}

- (void)viewDidLoad
{
    [super viewDidLoad];
}

// This method will be overridden by myTableViewDataSource
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return 1;
}

- (int)myRequiredMethod {
    return 2;
}

Subclassing is a great way to make reusable custom UI elements.

like image 6
SilenceDogood Avatar answered Oct 14 '22 05:10

SilenceDogood


I think, you should still go with a Controller class. I expect subclassing UITableView to be tedious work — if possible with reasonable amount at all.

There is no problem to have UIViewController/NoViewController implemented the delegate and datasource and yet assign another controller to a specific tableView. note, that the datasource and delegate don't need to be subclasses of UITableViewController.

have a look at this answer: Implement Delegate at Run Time?

My UITableView does not delegate to its view controller, so that's not the problem.

You have to have to use delegate and datasource, that is how TableViews are filled and configured. otherwise you will have to overwrite every method of UITableView — including private ones, a no-go if you want into AppStore. Recreating UITableView without subclassing it would be even easier.

like image 2
vikingosegundo Avatar answered Oct 14 '22 05:10

vikingosegundo