tableView:cellForRowAtIndexPath: never invoked but rows and headers are > 0 - objective-c

A tableView in my UIViewController has as data source a NSMutableArray.
After I've added a new object to the mutable array, I invoke [tableView reloadData], which correctly invokes:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
returning the correct update amount of elements in the array. However the method:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
is not called afterwards. I thought when I reloadData of a table view such method was invoked.
The sections method:
- (NSInteger)numberOfSectionsInTableView:(UITableView *)aTableView
always returns 1, in my code.
Thanks

What does the
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
method returns?
Have you managed it to return the count of your data source which is a NSMutableArray as you have mentioned?
In this method call :
[array count];

It was a thread issue... Ive fixed it with:
dispatch_async( dispatch_get_main_queue(), ^{
[table reloadData];
});

Related

how cellforrowatindexpath works in objective c [duplicate]

This question already has answers here:
How does cellForRowAtIndexPath work?
(3 answers)
Closed 5 years ago.
I am new to objective-c programming language.I create a table and create all method of table View .But i don't understand about CellForRowAtIndexPath.Please tell me some one how it work.
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
This is delegate method of UITableView. The returned object is of type UITableViewCell. These are the objects that you see in the table's rows. NSIndexPath has two this Section and Row.
It is called if you implement the UITableViewDataSource protocol in your view controller. A simpler way would be to add a UITableViewController class. I strongly recommend this because it Apple has some code written for you to easily implement the functions that can describe a table. Anyway, if you choose to implement this protocol yourself, you need to create a UITableViewCell object and return it for whatever row. Have a look at its class reference to understand re-usablity because the cells that are displayed in the table view are reused again and again(this is a very efficient design btw).
If your implementing custom cell then I will strongly recommend you use
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
to return only empty cell not set here. use thing like
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
CartTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"MyCart_Cell" forIndexPath:indexPath];
return cell;
}
and the use this delegate which will called just after cellForRow data source method
- (void) tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
if ([cell isKindOfClass:[CartTableViewCell class]])
{
CartTableViewCell *cell1 = (CartTableViewCell*)cell;
MyCartModel* data = [_myCartProductArray objectAtIndex:indexPath.row];
[cell1 setUpData:data];
}
}
and set data on UILabel in UITableviewcell custom class.

insertRowsAtIndexPaths inserts rows a

I'm trying to insert a row after the user has pressed return on the keyboard.
The code inside the textFieldShouldReturn method looks like this:
NSIndexPath *lastIndexPath = [NSIndexPath indexPathForRow:([self.tableView numberOfRowsInSection:([self.tableView numberOfSections] - 1)] - 1)
inSection:([self.tableView numberOfSections] - 1)];
[self.tableView insertRowsAtIndexPaths:#[lastIndexPath]
withRowAnimation:UITableViewRowAnimationRight];
This works fine until 10 rows are shown, after which a row is inserted at the beginning and then one and the end of the tableView.
How can I fix this?
I am pretty sure you have not updated your data. And one o both methods
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
of UITableViewDataSource returns wrong data.
UITableView only displays data. You should store it yourself somewhere.

cellForRowAtIndexPath is called when there is no row

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
if ([BGSearchParameter defaultSearchParameters].fetchedResults.count==0)
{
PO(#([self.tableView numberOfRowsInSection:0]));
PO(#([self tableView:nil numberOfRowsInSection:0]));
PO(#(indexPath.row));
while (false);
}
This is the result
self.tableView numberOfRowsInSection:0]): 20
#([self tableView:nil numberOfRowsInSection:0]): 0
Now, I do not know who call that cellForRowAtIndexPath.
Here is the screenshot
The debuggin windows shows that the main thread somehow call cellForRowAtIndexPath.
I usually fix this issue by returning some random UITableViewCell that's never displayed. Howerver, I think it's a bug.
What functions can call cellForRowAtIndexPath anyway besides tableReload and why it doesn't call
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
first?
It seems that my tableView still think there are 20 rows even though there are only 0 rows.
The issue seems to be your tableview is not refreshing. Please include this line in your code so that it will refersh each time:-
[yourTableView reloadData];
You can use the parameter "tableView" of this method to check whether the right instance of "UITableView" is called. For example, in the delegate method" - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section" add these code:
if(tableView== youwanttocheckTableView) {
//do what you want to do
}
You can also check which TableView instance have set its delegate equals "self" in this class.

How to populate the rootviewcontroller tableview with an NSMutableArray

I am trying to populate the tableview with an NSMutableArray, and I am having a really hard time with it.
This should be simple I'm thinking, but I can't get it to work.
Any help would be appreciated.
Thanks
You simply have to create an object implementing the UITableViewDataSource.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [self.yourArray count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
/* create your cell here */
AnObjectFromYourArray *myObject = [self.yourArray objectAtIndex:[indexPath row];
/* fill the cell with the info in my object */
return yourCell;
}
simple as that.
Greg

Initialize custom UITableViewCell

I'm trying to load a single custom cell into a UITableView and it keeps throwing an error
UITableView dataSource must return a cell from tableView:cellForRowAtIndexPath:
I have no idea why. I have linked my table view cell to the UITableViewCell definition in my code, but it keeps giving me this error. Here is my code; any help would be greatly appreciated.
#import "RegisterDeviceViewController.h"
#implementation RegisterDeviceViewController
#synthesize checkString;
#synthesize cellRegistration;
// The designated initializer. Override if you create the controller programmatically and want to perform customization that is not appropriate for viewDidLoad.
/*
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization.
}
return self;
}
*/
//Change UITableView Style to Grouped
- (id)initWithStyle:(UITableViewStyle)style {
// Override initWithStyle: if you create the controller programmatically and want to perform customization that is not appropriate for viewDidLoad.
style = UITableViewStyleGrouped;
if (self = [super initWithStyle:style]) {
}
return self;
}
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad {
self.title = #"Registration";
[super viewDidLoad];
}
// Customize the number of sections in the table view.
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
// Customize the number of rows in the table view.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return 1;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
if (indexPath.section == 1) {
if (indexPath.row == 1) {
return cellRegistration;
}
}
return nil;
}
//Pass search type over to rootViewController section2
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
/*
<#DetailViewController#> *detailViewController = [[<#DetailViewController#> alloc] initWithNibName:#"<#Nib name#>" bundle:nil];
// ...
// Pass the selected object to the new view controller.
[self.navigationController pushViewController:detailViewController animated:YES];
[detailViewController release];
*/
}
/*
// Override to allow orientations other than the default portrait orientation.
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
// Return YES for supported orientations.
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
*/
- (void)didReceiveMemoryWarning {
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Release any cached data, images, etc. that aren't in use.
}
- (void)viewDidUnload {
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (void)dealloc {
[super dealloc];
}
#end
Okay. That's not how UITableView works. When the table view needs to draw a cell (ie, a row); it invokes tableView:cellForRowAtIndexPath: on the object specified in the dataSource property. It's your job to return a UITableViewCell from that method. This is how Apple does it (and how you should do it):
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"AnIdentifierString"];
if (cell == nil)
{
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:#"AnIdentifierString"] autorelease];
}
cell.textLabel.text = #"This text will appear in the cell";
return cell;
}
The number of times that method will be invoked depends on the number of sections in the table view and the number of rows in each section. The process works like this:
Table View invokes the delegate method numberOfSectionsInTableView: on its dataSource (it knows it implements that method because the dataSource must adhere to the UITableViewDataSource protocol).
If numberOfSectionsInTableView: returns a number greater than zero, the table view will invoke the delegate method tableView:numberOfRowsInSection: on the dataSource. So if numberOfSectionsInTableView: returns 2, tableView:numberOfRowsInSection: will be invoked twice.
If each invocation of tableView:numberOfRowsInSection: returns a number greater than zero, the table view will invoke the delegate method tableView:cellForRowAtIndexPath: on the dataSource' So if tableView:numberOfRowsInSection: returns 5, tableView:numberOfRowsInSection: will be invoked five times (once for each individual row).
Your opportunity to customise how that cell appears is after you've received a useable cell, but before it is returned (where 'This text will appear in the cell' appears above). You can do quite a lot here; you should see the Class Reference for UITableViewCell to see everything you can do (all I've done is set it to show 'This text...'). The lines above that are a way for iOS to reuse cells for performance considerations. If you, for example, wanted to show a certain string from an array of strings, you could do this (notice the use of the indexPath variable): cell.textLabel.text = [someArrayYouHave objectAtIndex:indexPath.row];.
You wrote:
it keeps throwing an error
'UITableView dataSource must return a
cell from
tableView:cellForRowAtIndexPath:' But
I have no idea why..
But your -tableView:cellForRowAtIndexPath: says, in part:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
//...
return nil;
}
After reading the error message and looking at the code, do you not see the problem?
You are returning only one section, only one row
the section count and row count starts from 0.
Thats y you are getting this kinda error
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
if (indexPath.section == 0) {
if (indexPath.row == 0) {
//this checking is no necessary, anyway if you want use like this
//ensure that cellRegistration is UITableViewCell
return cellRegistration;
}
}
return nil;
}
Also refer this post for loading custom cells.
New iOS7+ solution optimized for Smoother Scrolling
You already can see old solutions but as far as huge amount of Apps will continue only iOS7+ support here is a way more optimized and correct solution.
Cell initialization
To initialize cell just call dequeueReusableCellWithIdentifier and iOS7+ systems are enough smart to handle if cell == nil or not. If during dequeue cell is nil system will automatically make a cell for you.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"cellIdentifier" forIndexPath:indexPath];
return cell;
}
Cell configuration
Then do your entire cell configuration in willDisplayCell method. Just create one method in your class that configures cell and here you go with better performance!
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {
[self configureCell:cell forRowAtIndexPath:indexPath];
}
- (void)configureCell:(UITableViewCell *)cell
forRowAtIndexPath:(NSIndexPath *)indexPath {
// Configure your cell
}