Step 1 demo – simple table
step 2 demo – pull out the data source
step 3 demo – pull out table view delegates
Step 1
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 |
#import "ViewController.h" @interface ViewController () <UITableViewDelegate, UITableViewDataSource> @property(nonatomic,strong) UITableView * tableView; @property (nonatomic, strong) NSArray * myData; @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view, typically from a nib. self.myData = [NSArray arrayWithObjects: @"Apple", @"Orange", @"Banana", nil]; self.tableView = [[UITableView alloc] initWithFrame:CGRectMake(0.0, 0.0, 320.0, 480.0f) style:UITableViewStylePlain]; self.tableView.delegate = self; self.tableView.dataSource = self; [self.view addSubview:self.tableView]; } // UITableViewDelegate methods - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { NSLog(@"you have selected row: %lu", indexPath.row); } // UITableViewDataSource methods - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { NSLog(@"%s", __FUNCTION__); UITableViewCell *cell = (UITableViewCell*)[tableView dequeueReusableCellWithIdentifier:@"tvcItems"]; if(cell==nil) { NSLog(@"%s - Creating new cell", __FUNCTION__); cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier: @"tvcItems"]; } [cell.textLabel setText:[self.myData objectAtIndex:[indexPath row]]]; return cell; } - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { NSLog(@"%s", __FUNCTION__); return 1; } - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { NSLog(@"%s", __FUNCTION__); if(section==0) return [self.myData count]; else return 0; } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; // Dispose of any resources that can be recreated. } @end |
Step 2 – pulling out the Data Source
In order to declare a data source, we first create an object that houses the data to represent the rows of data in your table view. Declare the protocol of UITableViewDataSource. This is so that your class conforms to it. And other delegates can then safely point to your object.
1 2 3 4 5 6 7 8 |
#import <Foundation/Foundation.h> #import <UIKit/UIKit.h> // make sure the protocol is public @interface MyData : NSObject <UITableViewDataSource> @end |
In the implementation, declare your data container, such as an array of strings.
Initialize your array in the initializer.
Then, in order satisfy the protocol that we conformed to (UITableViewDataSource), make sure you implement its needed methods.
Specifically, we implement
1 2 3 |
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 |
#import "MyData.h" @interface MyData () { } @property (nonatomic, strong) NSArray * myData; @end @implementation MyData -(id)init { if (self=[super init]) { NSLog(@"%s - initialized", __FUNCTION__); self.myData = [NSArray arrayWithObjects: @"Apple", @"Orange", @"Banana", nil]; } return self; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { NSLog(@"%s", __FUNCTION__); UITableViewCell *cell = (UITableViewCell*)[tableView dequeueReusableCellWithIdentifier:@"tvcItems"]; if(cell==nil) { NSLog(@"%s - Creating new cell", __FUNCTION__); cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier: @"tvcItems"]; } [cell.textLabel setText:[self.myData objectAtIndex:[indexPath row]]]; return cell; } - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { NSLog(@"%s", __FUNCTION__); return 1; } - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { NSLog(@"%s", __FUNCTION__); if(section==0) return [self.myData count]; else return 0; } @end |
Declare your Data class in ViewController, point dataSource to it
ViewController.m
We now declare our data class (which safely conforms to UITableViewDataSource )as a property.
1 2 3 4 5 6 7 8 9 |
#import "ViewController.h" #import "MyData.h" @interface ViewController () <UITableViewDelegate> @property(nonatomic,strong) UITableView * tableView; @property (nonatomic, strong) MyData * dataStore; @end |
Initialize the data object. Then we point the table view’s data source to it.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
@implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; self.tableView = [[UITableView alloc] initWithFrame:CGRectMake(0.0, 0.0, 320.0, 480.0f) style:UITableViewStylePlain]; self.tableView.delegate = self; self.dataStore = [[MyData alloc] init]; self.tableView.dataSource = self.dataStore; [self.view addSubview:self.tableView]; } ... ... @end |
Now if you run it, all UITableViewDelegate delegate messages are sent to your MyData object.
Step 3 – Pulling out the UITableViewDelegate
Now we’re going to create a View object that takes care of all the UITableViewDelegate delegates.
1 2 3 4 5 6 |
#import <Foundation/Foundation.h> #import <UIKit/UIKit.h> @interface MyView : NSObject <UITableViewDelegate> @end |
We implement delegate methods:
1 2 |
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath - (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath |
We log which row is selected.
We also check what kind of cell it is. Then we do something unique according to the cell type.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
#import "MyView.h" #import "MyTableViewCell.h" @implementation MyView // UITableViewDelegate methods - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { NSLog(@"%s - you have selected row: %lu", __FUNCTION__, indexPath.row); } - (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath { NSLog(@"%s %ld", __FUNCTION__, (long)indexPath.row); NSString * classType = [NSString stringWithUTF8String:object_getClassName(cell)]; NSLog(@"%@", classType); if ([classType caseInsensitiveCompare:@"MyTableViewCell"] == NSOrderedSame) { MyTableViewCell * temp = (MyTableViewCell*)cell; temp.descriptionLabel.text = @"This is a custom cell"; } else if ([classType caseInsensitiveCompare:@"UITableViewCell"] == NSOrderedSame) { cell.backgroundColor = UIColor.cyanColor; } } @end |
Declare your MyView property. It should conform to protocol UITableViewDelegate.
ViewController.m
1 2 3 4 5 6 7 8 9 10 11 12 |
#import "ViewController.h" #import "MyData.h" #import "MyView.h" @interface ViewController () @property(nonatomic,strong) UITableView * tableView; @property (nonatomic, strong) MyData * dataStore; @property (nonatomic, strong) MyView * myView; @end |
Then we instantiate it. Make sure your table view’s delegate points to the MyView object. Now all delegates sent from table view for its delegate functionality will be sent to your MyView object to be processed.
Notice that your ViewController is now nice and clean, with a clear separation of concern between data source delegates and tableview delegates.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
@implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; self.tableView = [[UITableView alloc] initWithFrame:CGRectMake(0.0, 0.0, 320.0, 480.0f) style:UITableViewStylePlain]; self.myView = [[MyView alloc] init]; // create the object that conforms to UITableViewDelegate self.tableView.delegate = self.myView; // assign tableView's delegate to it self.dataStore = [[MyData alloc] init]; // create the object that conforms to UITableDataSource self.tableView.dataSource = self.dataStore; // assign tableView's data source to it [self.view addSubview:self.tableView]; } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; // Dispose of any resources that can be recreated. } @end |