I already searched Google the entire day but I just can't figure out a solution for this one.
I am trying to implement a table view with custom cells in my iOS App. I'm using custom cells that display different images and Labels. Everything is working fine except that the Cells are too large for the table view. I know that I need to implement the heightForRowAtIndexPath method but it is never called.
I've tried setting the delegate for the TableView in the nib file and in the ShowPostsViewController in the code but nothing helps. I expect that the problem probably is that the dataSource is set but not the delegate. I can't understand why though.
Every solution I found until now says that the delegate is not set correctly. However, I'm pretty sure it is in my case?!
I'm grateful for any help. Here's my code:
ShowPostsViewController.h
#interface ShowPostsViewController : UIViewController <UITableViewDelegate, UITableViewDataSource>
#property (nonatomic, strong) IBOutlet UITableView *postsTableView;
#end
And ShowPostsViewController.m
#implementation ShowPostsViewController
#synthesize postsTableView;
- (void)viewDidLoad
{
[super viewDidLoad];
self.postsTableView.delegate = self;
self.postsTableView.dataSource = self;
NSLog(#"Delegate set");
[postsTableView beginUpdates];
NSMutableArray *tempArray = [[NSMutableArray alloc] init];
for(int i=0; i<8; i++){
[tempArray addObject: [NSIndexPath indexPathForRow:i inSection:0]];
}
[postsTableView insertRowsAtIndexPaths:tempArray withRowAnimation:UITableViewRowAnimationAutomatic];
NSLog(#"Updates Called");
[postsTableView endUpdates];
[postsTableView reloadData];
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return 8;
}
//PostTableViewCell is my custom Cell that I want to display
-(PostTableViewCell*)tableView: (UITableView*)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
PostTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"cell"];
if(!cell){
cell = [[PostTableViewCell alloc]initWithStyle:UITableViewCellStyleValue2 reuseIdentifier:#"cell"];
}
return cell;
}
//This method is not called for some reason
-(CGFloat)tableview: (UITableView*)tableView heightForRowAtIndexPath: (NSIndexPath*) indexPath{
NSLog(#"Height Method called");
CGFloat returnValue = 1000;
return returnValue;
}
//This method is called
-(NSInteger) numberOfSectionsInTableView:(UITableView *)tableView{
NSLog(#"Section Number called");
return 1;
}
#end
I've also got the tableView linked to the ShowPostsViewController in the Interface Builder.
Thank you all for your great support.
You are going to kick yourself for this mistake. You have implemented the method:
-(CGFloat)tableview: (UITableView*)tableView heightForRowAtIndexPath: (NSIndexPath*) indexPath
But the actual delegate method should be:
-(CGFloat)tableView: (UITableView*)tableView heightForRowAtIndexPath: (NSIndexPath*) indexPath
The only difference is the capital V in tableView. You have a lowercase v by mistake.
Try to make use of as much code completion in Xcode as you can to help avoid these types of mistakes.
Related
I've seen a number of people who have asked a similar thing, but answers to their questions are not the answers to mine.
1) I have created a single view application with an empty View Controller. In that, I dragged a new Table View (style Plain) with a single prototype cell of style Basic.
2) I am trying to learn about dynamically changing the behaviour of TableViews, so I have a mutable array called sectionRows, which will contain the number of rows per section. At the moment, a single section with a number of rows would be an achievement :)
3) In my ViewController.h I have set the delegates
#interface ViewController : UIViewController <UITableViewDataSource, UITableViewDelegate>
#end
I have also control-dragged from the TableView to the ViewController Yellow-Circle and set the datasource and delegate outlets.
4) In my ViewController.m, I have defined some global variables
#interface ViewController ()
{
NSMutableArray *sectionRows;
UITableView *myTableView;
}
The first is my data array (containing the number of rows per section and the second is a pointer to my TableView, which I have identified using a numeric View tag of '1'.
5) In my viewDidLoad, I initialize everything:
- (void)viewDidLoad
{
[super viewDidLoad];
myTableView = (UITableView *)[self.view viewWithTag:1];
sectionRows = [[NSMutableArray alloc] init]; // Create sectionarray
[sectionRows addObject:[NSNumber numberWithInteger:1]];
myTableView.dataSource = self;
myTableView.delegate = self;
[myTableView reloadData];
}
As you can see, I even make sure that I set the datasource and delegate again but this hasn't made any difference.
5) I have overloaded 3 methods.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
NSLog(#"Returning %# rows", [sectionRows objectAtIndex:section]);
return (NSInteger)[sectionRows objectAtIndex:section]; // the number referenced in the array...
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
NSLog(#"Returning %li sections", sectionRows.count);
return sectionRows.count; // the size of the sectionRows array
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = (UITableViewCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
// Configure the cell...
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
cell.textLabel.text = #"xxx";
NSLog(#"Setting cell to %#", cell);
return cell;
}
Now, when I run this, I am getting NSLog returning confirmation that there is a single section and a single row:
2014-07-27 19:58:34.599 TableViewTests[12877:60b] Returning 1 sections
2014-07-27 19:58:34.600 TableViewTests[12877:60b] Returning 1 rows
However, as you can see cellForRowAtIndexPath is not being called.
None of the other things I have seen point to what I am doing wrong. I am doing what I thought I did successfully in another simple project (to learn) but I must be doing something else differently.
Any ideas what I am missing?
Thanks in advance
Jon
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
NSLog(#"Returning %# rows", [sectionRows objectAtIndex:section]);
return (NSInteger)[sectionRows objectAtIndex:section]; // the number referenced in the array...
}
This is incorrect. You cannot cast what you get from your array to an NSInteger. It's a pointer. Assuming you store NSNumbers into the array:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
NSLog(#"Returning %# rows", [sectionRows objectAtIndex:section]);
return [[sectionRows objectAtIndex:section] integerValue]; // the number referenced in the array...
}
PRESENTATION
Mine is a simple project: It consists of a NavigationController, ViewController, and a “Search Bar and Search Display Controller”
My .h file is
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController <UISearchDisplayDelegate, UITableViewDataSource, UITableViewDelegate>
#end
and my .m file is
#import "ViewController.h"
#interface ViewController ()
#property(nonatomic,strong)NSMutableArray *data;
#end
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
self.searchDisplayController.displaysSearchBarInNavigationBar = YES;
self.data=[[NSMutableArray alloc]init];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark - data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)aTableView {
// Return the number of sections.
return 1;
}
- (NSInteger)tableView:(UITableView *)aTableView numberOfRowsInSection:(NSInteger)section {
// Return the number of rows in the section.
return [_data count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"CellIdentifier";
// Dequeue or create a cell of the appropriate type.
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] ;
cell.accessoryType = UITableViewCellAccessoryNone;
}
// Configure the cell.
cell.textLabel.text = [NSString stringWithFormat:#"Row %d", indexPath.row];
cell.textLabel.text = [NSString stringWithFormat:#"Row %d: %#", indexPath.row, [_data objectAtIndex:indexPath.row]];
return cell;
}
#pragma mark - delegate
- (BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString
{
[NSTimer scheduledTimerWithTimeInterval:2 target:self selector:#selector(mockSearch:) userInfo:searchString repeats:NO];
return NO;
}
- (void)mockSearch:(NSTimer*)timer
{
[_data removeAllObjects];
int count = 1 + random() % 20;
for (int i = 0; i < count; i++) {
[_data addObject:timer.userInfo];
}
[self.searchDisplayController.searchResultsTableView reloadData];
}
#end
And that’s the entire program. What does it do? User makes a search and the data is displayed in a TableView (similar to a google search).
PROBLEM
I need to use a CustomTableViewCell for my table. And I need to build the TableViewCell from the storyboard (easy to visualize). I am stuck with the storyboard part. How do I place a TableViewCell on the storyboard without a TableView to place it in? I had an idea, I tried it, but it didn’t work. Here is what I did. I placed a “never-to-be-used” TableViewController in the storyboard whose sole purpose is to hold my CustomTableViewCell. Then in code I subclass TableViewCell and use IBOutlet to link the sub-views of the storyboard TableViewCell to my CustomTableViewCell . And then I used my cell as CustomTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];. This didn’t work. The tableView remained blank. And my guess for the failure is that CustomTableViewCell does not belong to the tableView being dequeued from.
I need the UISearchBar to always stay inside the NavigationBar. But so far self.searchDisplayController.displaysSearchBarInNavigationBar = YES; is not doing it. When I first start the app the searchBar is inside the NavigationBar. But as soon as I click on it, it smacks itself right in the middle of my scene/screen and never leaves.
I need to add a Header to my TableView. Which I thought of doing the same way as the CustomTableViewCell, but with a UIView parent class. But again, the CustomTableViewCell portion failed.
PLEA
Thank you for any help you can provide me.
UPDATE
All I am trying to do is allow my users to launch a server side search and view the results in a tableView. This is such a basic thing, I image many people here have done this a number of times. Being new to iOS, I am stuck. But at this point, I have posted my entire project (anyone can reconstruct it), and I have explained in details all the ways I tried to solve the problem. So if someone has a sample project they don’t mind sharing, it would help very much. Or if you know of a git project please put a link to it. Thanks.
If you want to make a stand-alone view (not in a view controller) in IB, then you should do it in a xib file, not a storyboard. You can have as many storyboard and xib files in an app as you want; they can be mixed freely. To make a new cell in a xib file, just go to New File --> User Interface --> Empty then drag in a UITableViewCell. Add any subviews you want, and in your table view controller (or whatever class is your table view data source), register the xib file with, registerNib:forIdentifier: (usually, you do this in viewDidLoad).
I am a beginner in Objective-C & iPhone development.
I add dynamically cells in a TableView. I want to set labels's text properties with an array. I saw many tutorials, and I searched during several hours but labels are never filled.
My code is :
- (void)insertNewObject
{
for (NSInteger ic=0; ic<((pages.count)); ++ic) {
NSLog(#"%d", ic);
NSDictionary *monDico = pages[ic];
menu = [monDico objectForKey:#"Name"];
NSIndexPath *indexPathTable = [NSIndexPath indexPathForRow:0 inSection:0];
[self.tableView insertRowsAtIndexPaths:#[indexPathTable] withRowAnimation:UITableViewRowAnimationAutomatic];
[self.tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0]]; // I try include & exclude : never call
}
[self.tableView reloadData];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"Cell" forIndexPath:indexPath];
cell.textLabel.text = menu[indexPath.row];
NSLog(#"%#%#", #"Cell Label = ", cell.textLabel.text);
return cell;
}
Please note that insertNewObject method is called during viewDidLoad execution.
I use a breakpoint in the cellForRowAtIndexPath method : it never calls ! I try with :
explicit calling
forcing reloadData method
but did not work too.
Can you please tell me why ?
Thanks in advance.
If cellForRowAtIndexPath is not being called then most likely you have not set:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [menu count]; // indicates the number of rows in your table view
}
This method needs to return the number of rows you expect to render within your table view. The default is 0 = no rows. I'm assuming you want to show all the items in your menu array so simply return [menu count].
Check this: UITableViewDataSource Protocol Reference
If you want to access to textLabel property of your cell, then it must be style of: UITableViewCellStyleDefault. Or, if you use storyboard, then set Cell's style to Basic.
And, of course, make sure that you have set delegate and datasource properties of your tableView.
- (void)viewDidLoad
{
[super viewDidLoad];
//...
self.tableView.delegate = self;
self.tableView.dataSource = self;
}
------------------EDIT------------------
If you're using UITableViewController, then no more need to set delegate and dataSource properties manually, because they will automatically set by UITableViewController when your view did load.
If cellForRowAtIndexPath: method still not being called, then make sure that following methods that you implemented, both returns value >0:
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView;
and
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
Set a breakpoint before return and see returning values, or just NSLog them before returning.
I have created .h and .m files for UITableView called mainTableViewgm.h and mainTableViewgm.m resp. and I am calling -initWithFrame: method from my main view controller to this mainTableViewgm.m implementation file
[[mainTableViewgm alloc]initWithFrame:tableViewOne.frame]
Note that this tableview is in my main view controller. But I have created separate files for the tableView and have also set the custom class to mainTableViewgm in storyboard.
the -initWithFrame: methods appears as follows
- (id)initWithFrame:(CGRect)frame
{
//NSLog(#"kource data");
self = [super initWithFrame:frame];
if (self)
{
[self setDelegate:self];
[self setDataSource:self];
[self tableView:self cellForRowAtIndexPath:0];
[self tableView:self numberOfRowsInSection:1];
// Initialization code
}
return self;
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
NSLog(#"kource data");
return 1;
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSLog(#"kource data2");
UITableViewCell*cellOne =[[UITableViewCell alloc]init];
cellOne.detailTextLabel.text=#"text did appear";
return cellOne;
}
the -initWithFrame: is being called fine along with the 'if (self)' block in this method. But the problem is numberOfRowsInSection: and cellForRowAtIndexPath: are not being automatically called here . kource data/kource data2 never appear in log. What do I do to load the table? Are the delegate/datasource being set incorrectly?
I must mention that I have also set the UITableViewDelegate and UITableviewDataSource protocols:
#interface mainTableViewgm : UITableView <UITableViewDelegate,UITableViewDataSource>
#end
Help will be much appreciated. Thank you.
Your tableview is not loaded when the controller is initializing, so you cannot do that in the init methods. You have to move your code to the viewDidLoad method.
Also you are not setting the delegate and datasource on the tableview object (probably a type, you are setting them on the view controller). It should look like this:
- (void)viewDidLoad:(BOOL)animated {
[super viewDidLoad:animated];
[self.tableView setDelegate:self];
[self.tableView setDataSource:self]; // <- This will trigger the tableview to (re)load it's data
}
Next thing is to implement the UITableViewDataSource methods correctly. UITableViewCell *cellOne =[[UITableViewCell alloc] init]; is not returning a valid cell object. You should use at least initWithStyle:. And take a look how to use dequeueReusableCellWithIdentifier:forIndexPath:. A typical implementation would look like this:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
// Reuse/create cell
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
// Update cell contents
cell.textLabel.text = #"Your text here";
cell.detailTextLabel.text=#"text did appear";
return cell;
}
I can't believe I've been doing XCode programming for two years, and still hit this issue.
I had the same problem with XCode 6.1 - I was setting my UITableView's delegate & dataSource in the viewWillAppear function, but none of the delegate functions were kicking in.
However, if I right-clicked on the UITableView on the Storyboard, the circles for delegate and dataSource were empty.
The solution, then, is to hold down the CTRL key, and drag from each of these circles up to the name of your UIView which contains your UITableView:
After doing this, my UITableView happily populated itself.
(So, we're upto v6.1 of XCode now are we ? Do you think Apple ever going to make this thing, you know, friendly...? I would quite like to add a Bookmark in my code... that'd be a nice feature.)
I have an nslog that is successfully telling me that the information I will load into dynamic cells is there. However, I've discovered that my tableView is not loading the array "dogs" with object "dogs" at all because the nslog for name11Label is returning null despite the fact that there is a value for dogs in viewDidLoad. What would I need to do to initiate the tableView? (.h does have an iboutlet and a property(just to make sure) for my "tableView" and also has as well as and import for cell11.h)
.m file
-(void)viewDidLoad{
...
self.tableview.delegate = self;
...
}
- (NSInteger)tableView:(UITableView *)table numberOfRowsInSection:(NSInteger)section {
if ( dogs != NULL ) {
return [dogs count];
}
return 0;
}
- (UITableViewCell *)tableView:(UITableView *)tv cellForRowAtIndexPath:(NSIndexPath *)indexPath {
Cell11 *cell = [tableView dequeueReusableCellWithIdentifier:#"Cell11"];
if (cell == nil)
{
cell = [[[Cell11 alloc] initWithFrame:CGRectZero reuseIdentifier:#"Cell11"] autorelease]; //I know that this method is depreciated, but it is not the source of this problem
}
NSDictionary *itemAtIndex =(NSDictionary *)[dogs objectAtIndex:indexPath.row];
cell.name11Label.text = [itemAtIndex objectForKey:#"dogs"];
NSLog(#"dogs array = %#", dogs); //returns correct information of the object dogs
NSLog(#"%#", cell.name11Label.text); //returning null even though "dogs" in viewDidLoad is showing a result;
return cell;
}
Cell11.h
#import <UIKit/UIKit.h>
#interface Cell11 : UITableViewCell
#property (nonatomic, strong) IBOutlet UILabel *name11Label;
#end
Cell11.m
#import "Cell11.h"
#implementation Cell11
#synthesize name11Label;
#end
Change:
Cell11 *cell = [tableView dequeueReusableCellWithIdentifier:#"Cell11"];
to
Cell11 *cell = [tv dequeueReusableCellWithIdentifier:#"Cell11"];
tableView is probably not hooked up right.
The nslog statement will never get called. Move it above:
NSLog(#"%#", cell.name11Label);
return cell;
Also you are initializing the cell with cgrect zero which won't display anything. Make sure it has a height and width that are expecting (e.g. CGRectMake(0.0f, 0.0f, 320.0f, 50.0f))
If the cell still doesn't display, are you calling reloadData on the tableview after the array dogs is set up?
Have you assigned your UITableView's "dataSource" property to the object with the UITableViewDataSource protocol (the above methods)?
First of all: The NSLog after the return will never be called.
NSLog(#"%#", cell.name11Label);
return cell;
}
Second: Control drag from you tableview of the interface builder to your class. And make sure the connection dataSource is properly connected.