I'm subclassing UITableView in my app. It's set up to be it's own delegate.
#interface TableView : UITableView <UITableViewDelegate, UITableViewDataSource>
#property (nonatomic, assign) id delegate;
- (id)initWithFrame:(CGRect)frame;
#end
#implementation TableView
#synthesize delegate;
- (id)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
UIView *footerView = [[UIView alloc] initWithFrame:CGRectMake(0, self.frame.size.height-144, self.frame.size.width, 40)];
super.delegate = self;
super.dataSource = self;
self.tableFooterView = footerView;
}
return self;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return 15;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
return [self.delegate tableView:tableView cellForRowAtIndexPath:indexPath];
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[tableView deselectRowAtIndexPath:indexPath animated:YES];
NSLog(#"Selected row!");
}
#end
Now, what I don't understand is how I TableView can be the delegate of UITableView, but also have a different delegate property that it pipes some functions to sometimes. So, I'd like for - for example - numberOfRowsInSection to be handled by this class, but for - for example - didSelectRowAtIndexPath to be forwarded to the UIViewController or whatever's presenting it.
Each of the delegate methods have a property (UITableView *)tableView you can use this to identify which table views action to be performed
Eg lets say you have 2 table views tableView1 & tableView2 now do something like this
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
if tableView == self {
return [self.delegate tableView:tableView cellForRowAtIndexPath:indexPath];
} else if tableView == tableView2 {
// Do something
}
}
You can do the same concept using super and self calls
EDIT
Create a property called customDelegate, now in your ViewController set customDelegate = self and keep the TableView's delegate same
Now when you wish the class should handle the call just don't do anything as the behaves would be default
But if you wish that your viewController should handle the call then just pipe it using that customDelegate property
Eg
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
if <SOME_CONDITION> {
// This will cause the TableView's delegate to be called
return [self.delegate tableView:tableView cellForRowAtIndexPath:indexPath];
} else {
// We wish the ViewController to handler this action then
return [self.customDelegate tableView:tableView cellForRowAtIndexPath:indexPath];
}
}
Related
I have a UITableView in my app and I'm trying to pull it's delegate methods into a separate UITableViewDelegate. This is what the code looks like:
RestaurantViewDelegate *delegate = [[RestaurantViewDelegate alloc] initWithRestaurant:self.restaurant andRecommended:self.recommended];
self.tableView = [[UITableView alloc] initWithFrame:CGRectMake(0, 235.0f, self.view.frame.size.width, self.view.frame.size.height-235)];
self.tableView.delegate = delegate;
self.tableView.dataSource = delegate;
[self.view addSubview:self.tableView];
And this is what RestaurantViewDelegate looks like:
// RestaurantViewDelegate.h
#interface RestaurantViewDelegate : NSObject <UITableViewDelegate>
#property (nonatomic, strong) NSArray *recommendations;
#property (nonatomic, strong) Restaurant *restaurant;
- (id)initWith Restaurant:(Restaurant *)restaurant andRecommended:(NSArray *)recommendations;
#end
and
// RestaurantViewDelegate.m
#implementation RestaurantViewDelegate
#synthesize recommendations = _recommendations;
#synthesize restaurant = _restaurant;
- (id)initWith Restaurant:(Restaurant *)restaurant andRecommended:(NSArray *)recommendations {
self = [super init];
if ( self != nil ) {
_recommendations = recommendations;
_restaurant = restaurant;
}
return self;
}
#pragma mark - UITableViewDataSource
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
NSLog(#"Recommendations: %d", [_recommendations count]);
return [_recommendations count];
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
return 48.0f;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *MyIdentifier = #"MyIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:MyIdentifier];
if (cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:MyIdentifier];
}
return cell;
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
#end
However, when I run my app and click on a cell, all cells disappear. I really don't know what's causing this. Any ideas as to what I'm doing wrong?
This is a very interesting problem. Remember that in ARC (Automatic reference counting ), an object will be retained only as long as a strong reference to it is maintained. Remember, the 'delegate's are always weak, and in your case it means, once you come out of the scope, where you create the delegate object and setup the table view, there will no longer any delegate object retained. This is the reason you might not see anything happening when you try to reload the table view. Make the delegate object RestaurantViewDelegate a member of your controller. And check..
I currently have a MatchCenterViewController that I want to programmatically turn into a UITableViewController. I've attempted to do so below based on tutorials I've found, but it doesn't seem to be appearing.
MatchCenterViewController.m:
#import "MatchCenterViewController.h"
#import <UIKit/UIKit.h>
#interface MatchCenterViewController () <UITableViewDataSource, UITableViewDelegate>
#end
#implementation MatchCenterViewController
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"newFriendCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"newFriendCell"];
if (cell == nil) {
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
}
//etc.
return cell;
}
- (void)viewDidLoad
{
[super viewDidLoad];
}
#end
As a minimum, you need to implement the following methods
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
And you need to set the delegate and datasource, typically in viewDidLoad
- (void)viewDidLoad
{
[super viewDidLoad];
self.tableView.dataSource = self;
self.tableView.delegate = self;
}
Also, you need an IBOutlet to the table view if the table view was created in storyboard, or a property for the table view, if the table view was created in code.
I implemented a UITableview with all methods.
When the UITableviewController is the initial View Controller, it works fine, I can swipe to delete.
But when the UITableViewController is part of my project and reached by pushing the view, I can't swipe to delete. It seems the application doesn't always detect the swipe or something like this, because sometimes, the delete button appears.
This is a very simple project, there is no big operation.
(I'm using Google Analytics et Google Adsense library, but not in this view controller.)
---
EDIT : Some code and a question, the code of the previous screen may influence the performance of the uitableviewcontroller ?
My storyboard is like this :
[Navigation controller] --> [Root View Controller] --> [Table View Controller]
Code :
VerreTableViewController.h
#interface VerreTableViewController : UIViewController <UITableViewDataSource,UITableViewDelegate>
#property (weak, nonatomic) IBOutlet UITableView *table_view_verres;
#end
VerreTableViewController.m
#interface VerreTableViewController ()
#end
NSArray *objects_verres;
#implementation VerreTableViewController
- (void)viewDidLoad
{
[super viewDidLoad];
objects_verres = [Verre allWithOrder:#{#"date_prise" : #"DESC"}];
_table_view_verres.delegate = self;
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return objects_verres.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [_table_view_verres dequeueReusableCellWithIdentifier:#"cell" forIndexPath:indexPath];
UILabel *lbl_nom = (UILabel *)[cell viewWithTag:10];
UILabel *lbl_date = (UILabel *)[cell viewWithTag:11];
NSManagedObject *matches = objects_verres[indexPath.row];
lbl_nom.text = [matches valueForKey:#"nom_alcool"];
lbl_date.text = [[matches valueForKey:#"date_prise"] formattedDateWithFormat:#"HH:mm - dd/MM/yyyy"];
return cell;
}
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath
{
return YES;
}
// Override to support editing the table view.
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
if (editingStyle == UITableViewCellEditingStyleDelete) {
//code to delete
}
}
I would point you to this post: Swipe to Delete not working
Make sure you implement all the necessary methods, and you don't have a unusual view hierarchy/code running on the app delegate.
I vaguely remember an issue with storyboards and tableview controllers that are embedded inside a view controller. Perhaps someone else can shed more light on this.
i have created a UItableView named _tableView, here is the code for table view in view.m
- (void)viewDidLoad
{
[super viewDidLoad];
tableData = [NSArray arrayWithObjects:#"Team Members",#"MembershipStatus",#"relation of status",#"Registerd events", nil];
[_tableView setUserInteractionEnabled:TRUE];
[_tableView reloadData];
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [tableData count];
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return 54;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
[newCell setUserInteractionEnabled:TRUE];
newCell.textLabel.text = [tableData objectAtIndex:indexPath.row];
return newCell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSLog(#"id");
}
while executing the code I got the table correctly. But when i am selecting one of the list item it won't respond. (i.e., the NSLog is not working). did i miss something ?? or what i do wrong ??
In your -viewDidLoad write:
[_tableView setDelegate:self];
check if the tableview's delegate is set to your viewController
#interface MyView : UIViewController <UITableViewDelegate, UITableViewDataSource>
in viewDidLoad:
self.tableview.delegate=self;
Check with your code
#interface ClassName : UIViewController <UITableViewDelegate, UITableViewDataSource>
in viewDidLoad:
self.tableView.delegate = self;
self.tableView.dataSource = self;
or
_tableView.delegate = self;
_tableView.dataSource = self;
check in .h file
#interface MyView : UIViewController is set or Not. if its not set then Set 1st there.
then in .m File while Creating TableView there
you just write
_tableView.delegate = self;
_tableView.dataSource = self;
Why isn't the numberOfSectionsInTableView method not being called? It's called if I add [self.tableView reloadData] in viewDidLoad, but even then, cellForRow does not get called.
Edit: I updated the following code to register the nib for the UITableViewCell.
In a UIViewController, I have:
- (void)viewDidLoad
{
[super viewDidLoad];
XXFeedTableViewController *tableViewController = [[XXFeedTableViewController alloc] initWithStyle:UITableViewStylePlain];
tableViewController.view.frame = self.view.bounds;
[self addChildViewController:tableViewController];
}
XXFeedTableViewController.h
#interface XXFeedTableViewController : UITableViewController
#end
XXFeedTableViewController.m
#import "XXFeedTableViewController.h"
#import "XXFeedTableViewCell.h"
#interface XXFeedTableViewController ()
#end
#implementation XXFeedTableViewController
- (id)initWithStyle:(UITableViewStyle)style {
self = [super initWithStyle:style];
if (self) {
}
return self;
}
- (void)viewDidLoad {
[super viewDidLoad];
[self.tableView registerNib:[UINib nibWithNibName:#"XXFeedTableViewCell" bundle:nil] forCellReuseIdentifier:#"XXFeedTableViewCell"];
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return 5;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"XXFeedTableViewCell";
XXFeedTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
cell.textLabel.text = #"Hey";
return cell;
}
#end
Apple docs say:
If no nib file is specified or if the nib file defines no data source
or delegate, UITableViewController sets the data source and the
delegate of the table view to self. When the table view is about to
appear the first time it’s loaded, the table-view controller reloads
the table view’s data.
Try this, and see if it works. This is the way Apple recommends now with a nib based cell.
-(void)viewDidLoad {
[super viewDidLoad];
[self.tableView registerNib:[UINib nibWithNibName:#"XXFeedTableViewCell" bundle:nil] forCellReuseIdentifier:#"XXFeedTableViewCell"];
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return 5;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"XXFeedTableViewCell";
ROFeedTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
cell.textLabel.text = #"Hey";
return cell;
}
After Edit:
In your initial controller, you should add the table view controller as a child controller before you add its subview:
XXFeedTableViewController *tableViewController = [[XXFeedTableViewController alloc] initWithStyle:UITableViewStylePlain];
self addChildViewController:tableViewController];
tableViewController.view.frame = self.view.bounds;
[self.view addSubview:tableViewController.view];
[tableViewController didMoveToParentViewController:self];