I have created an tableview with an array. There are 7 items in my array. But in cellForRowAtIndexPath method i'm unable to get indexpath.row == 6. What could be the reason.
Code is below for this.
-(void)viewDidLoad
{
[super viewDidLoad];
self.menu = [NSArray arrayWithObjects:#"Home",#"ansCategory",#"askQue",#"myQue",#"likedQue", #"topQue", #"topUser",nil];
}
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return 1;
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
// NSLog(#"count::::::%d",self.menu.count);
return self.menu.count;
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *cellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:cellIdentifier];
NSLog(#"rows:%#",indexPath);
NSLog(#"row:%#",[self.menu objectAtIndex:indexPath.row]);
}
return cell;
}
I'm getting following out put:
[here] (https://www.dropbox.com/s/pz6t34xr7l4glxz/menu1.png)
first index is overlaying on last one.
The cell is reused.
Put your log statement outside of the if(cell=nil):
Here is the working example for outputting the contents of the array in a tableview. Item with index 6 which is the seventh in the array ("topUser") is in red.
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *cellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:cellIdentifier];
}
NSLog(#"rows:%#",indexPath);
NSLog(#"row:%#",[self.menu objectAtIndex:indexPath.row]);
cell.textLabel.text = self.menu[indexPath.row];
if (indexPath.row == 6)
cell.textLabel.textColor = [UIColor redColor];
return cell;
}
For N items the last indexpath is (N-1)
Thus, if you have 10 items, then the index path of last item is 9 because the indexpath of 1st item in array is 0.
indexPath of items starts with 0 and not 1.
Try to access the index path in your answer like below in your code
Instead of :
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:cellIdentifier];
NSLog(#"rows:%#",indexPath);
NSLog(#"row:%#",[self.menu objectAtIndex:indexPath.row]);
}
Write
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:cellIdentifier];
}
//Access the indexPath outside here...
//Because once the cells are created and not nil
//then the above scope will be bypassed.
NSLog(#"rows:%#",indexPath);
NSLog(#"row:%#",[self.menu objectAtIndex:indexPath.row]);
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
gets executed whenever the new row is needed to be created and added to the tableview.The tableview populates row such that when it needs to be dispayed on screen it is created by calling the very same method.So If your 7 th row is not visible on screen the method wont get executed for row 7 ie indexpath.row 6 and so to get the method to log the 7 th row just scroll down so that that cell can be made visible by the table and it will execute the method and you can have the log
I changed my code to following line and it worked.
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:nil];
Related
I'm trying to use "reloadData" method on a uitableView, it seems like it works (both dataSource method are being called) and when I debug "cellForRowAtIndexPath" the cell that it returns is the correct cell) but I can't see the cell (numberOfRowsInSection is changing and adding blank space for each new cell - So it's not seems to be a threads problem). For example, if I have in the tableView 5 "names" (my data array called "namesArray") and I add 2 there will be 5 names and 2 nil cells presented on the tableView. The problem seems to be with cellForRowAtIndexPath.
cellForRowAtIndex:
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
//Creating "cellIdentifier"(NSString) with "Cell" as the value
NSString *cellIdentifier=#"Cell";
[tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:cellIdentifier];
//Creating a default cell using "cellIdentifier"(NSString)
UITableViewCell *cell=[tableView dequeueReusableCellWithIdentifier:cellIdentifier forIndexPath:indexPath];
if (cell==nil) {
cell=[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
}
cell.textLabel.text=[namesArray objectAtIndex:indexPath.row];
//Returning cell
return cell;
}
numberOfRowsInSection:
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return self.namesArray.count;
}
-(void)addNameToNamesArray:(NSString*)name
{
[self.namesArray addObject:name];
NSLog(#"namesArray lastObject: %#",[self.namesArray lastObject]);
//NSLog print: The correct name (the one that was added)
[self.tableView reloadData];
}
screenshot for "5 names and 2 nil cells":
Do you have any idea what can it be?
You call
[tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:cellIdentifier];
inside cellForRowAtIndexPath!
Don't you think that's a bit late? And if it worked, you would be calling it a bit often?
And if dequeue... returns nil when a class is registered, something is badly wrong.
change to
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
//Creating "cellIdentifier"(NSString) with "Cell" as the value
static NSString *cellIdentifier=#"Cell";
//[tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:cellIdentifier];
//Creating a default cell using "cellIdentifier"(NSString)
UITableViewCell *cell=[tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (cell==nil) {
cell=[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
}
cell.textLabel.text=[namesArray objectAtIndex:indexPath.row];
//Returning cell
return cell;
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return self.namesArray.count;
}
set the outlet of tableview and then in addNameToNamesArray method after adding elements reload the tableview
This is likely because you have updated the data in your array, but the table view hasn't accessed that data yet, leading to the nil cells that you see. Since your cells load properly with the initial 5 element in your array, it's probable that you simply haven't refreshed the table view's data. Try using [tableView reloadData] after you have added the new elements to your array.
EDIT 1
What about changing your cellForRowAtIndexPath code to this:
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
//Creating "cellIdentifier"(NSString) with "Cell" as the value
NSString *cellIdentifier=#"Cell";
//Creating a default cell using "cellIdentifier"(NSString)
UITableViewCell *cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
cell.textLabel.text = [self.namesArray objectAtIndex:indexPath.row];
NSLog(#"name: %#", cell.textLabel.text);
//Returning cell
return cell;
}
Let us know the output of NSLog.
1.Make sure you have initialized self.namesArray in viewDidLoad
Try the following:
[tableView registerClass:[UITableViewCell class]forCellReuseIdentifier:cellIdentifier];
like below:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *cellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (!cell) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
}
cell.textLabel.text = [namesArray objectAtIndex:indexPath.row];
return cell;
}
Your code is perfectly alright. There can be some possibilities that its not working for you.
You are not initialising your datasource i.e NSMutableArray in your case.
It depends how you are calling addNameToNamesArray method.
If you can share your whole code for that class as how you are calling method and every delegates you are using.
I wish to display a custom view in between a table view if a particular cell's attribute matches some condition.
Something like this
Row 1
Row 2
Row (n) (matches condition)
--------------------------- (Custom View)
Row (n+1)
Row (n+2)
I am using a TableView and TableViewDelegate in a ViewController
You also need TableDataSource with the delegate. The just return another cell class, depending on the condition of the object in source array in the tableView cellForRowAtIndexPath: method of the table delegate.
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
MyObjectClass * objectFromArray = [sourceArray.objectAtIndex: indexPath.row];
if(condition on MyObjectClass or index row){
static NSString *MyIdentifier = #"MyReuseIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:MyIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:MyIdentifier];
}
return cell;
}
}else{
static NSString *MyOtherIdentifier = #"MyOtherReuseIdentifier";
NewUITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:MyIdentifier];
if (cell == nil) {
cell = [[NewUITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:MyOtherIdentifier];
}
return cell;
}
}
}
I have a TableView with data from parse.com where I Placed order to descend according to Functional queryfortable with the "Date" selected by a pickerdate. Now the earliest date turns out to be the last cell and only in the last cell I would like to add a image ... In this specific case, how could I do? This is more 'complicated for me: (
I need to insert an image only in the last cell
Thanks Rory
If you're using PFQueryTableViewController then you should be using a custom subclass of it.
/// MyPFQueryTableViewController.h
#interface MyPFQueryTableViewController : PFQueryTableViewController
self.objects is the Datasource array the PFQueryTableViewController class uses for each table row.
You have to check whether the indexPath.row is the last object inside the self.objects array.
Within MyPFQueryTableViewController.m you override the cellForRowAtIndexPath method:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath object:(PFObject *)object {
static NSString *CellIdentifier = #"Cell";
PFTableViewCell *cell = (PFTableViewCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[PFTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
// Configure the cell
// Is this the last displaying cell?
if( indexPath.row == ([self.objects count]-1) )
{
cell.imageView.image = [UIImage imageNamed:#"End_Of_List.jpg"];
cell.textLabel.text = #"";
}
else
{
cell.textLabel.text = [object objectForKey:self.textKey];
}
return cell;
}
I'm trying to build an UITableView with some long texts inside each cell. Cells are without AccessoryView, except for one cell (the 8th one), that is a sort of button to open a detail view.
Consider this code:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
CGSize size = [[quotes objectAtIndex:indexPath.row] sizeWithFont:16 constrainedToSize:CGSizeMake(self.view.frame.size.width, CGFLOAT_MAX)];
return size.height+20;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
cell.textLabel.lineBreakMode = UILineBreakModeWordWrap;
cell.textLabel.numberOfLines = 0;
cell.textLabel.text = [quotes objectAtIndex:indexPath.row];
if(indexPath.row==7){
[cell setAccessoryType:UITableViewCellAccessoryDetailDisclosureButton];
}
return cell;
}
It works, but the problem is that when I scroll to the bottom of the Table (the 8th is also the last row) and then I go back to the upper side, another AccessoryView is added to a random point (more or less the 3rd cell, but I don't know if it is inside of it or is floating around randomly).
Is it something related to cell reusing by iOS? How can I avoid it?
Thanks in advance.
You have to explicitly set no disclosure button to every cell but the one that you wish to have disclosure. This way when the cell gets reused elsewhere its disclosure indicator is removed:
if(indexPath.row==7){
[cell setAccessoryType:UITableViewCellAccessoryDetailDisclosureButton];
}else{
[cell setAccessoryType:UITableViewCellAccessoryNone];
}
The cell is being reused (as demonstrated by your call to -dequeueReusableCellWithIdentifer).
The answer is to set the cell to wanted defaults after it's been dequeued, or add an else clause to the if statement to handle it.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
cell.textLabel.lineBreakMode = UILineBreakModeWordWrap;
cell.textLabel.numberOfLines = 0;
cell.textLabel.text = [quotes objectAtIndex:indexPath.row];
// Set to expected default
[cell setAccessoryType:UITableViewCellAccessoryNone];
if(indexPath.row==7){
[cell setAccessoryType:UITableViewCellAccessoryDetailDisclosureButton];
}
return cell;
}
This is due to cell reuse as you surmise. You must explicitly set UITableViewCellAccessoryNone for cells at index paths other than 7.
I am working on a project where I need to populate the cells in a table and have them show on the screen. I've got the table to show but now data is being shown in the cells. I've tried using breakpoints and found that this method never gets called. The method just before it (numberOfRowsInSection) does get called. Any suggestions?
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
Resident *aResident = (Resident *)[appDelegate.residents objectAtIndex:indexPath.row];
cell.textLabel.text = aResident.name;
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
return cell;
}
Have you set the delegate and datasource for the TableView ?
Yeah, numberOfRowsInSection probably returns 0. Show it and where you populate your data source.