This is the abridged code for my cellForRowAtIndexPath UITableView delegate method:
- (UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"blahblahblah"];
if (cell == nil) {
// No cell to reuse => create a new one
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:#"blahblahblah"] autorelease];
}
cell.textLabel.text = #"";
cell.detailTextLabel.text = #"";
cell.backgroundView = NULL; //problem here
// Initialize cell
//blah blah blah
//now to the good part...
if(indexPath.section == 1) {
cell.backgroundView = deleteButton;
cell.userInteractionEnabled = YES;
cell.textLabel.text = nil;
cell.detailTextLabel.text = nil;
}
else if(indexPath.section == 0) {
NSLog(#"section: %i row: %i", indexPath.section, indexPath.row);
switch (indexPath.row) {
case 0:
cell.textLabel.text = #"foobar";
//more stuff
break;
//lots more cases
default:
break;
}
}
return cell;
}
My problem is that the first cell in section 1 (section 0 has 10 cells, section 1 has only 1 cell) is getting assigned the information that is only supposed to be assigned to cell 0 of the first section. So, instead of getting the deleteButton background and etc, it gets the label title "foobar". I'm not really sure why this is happening, because my if statements are pretty clear. Any ideas?
Edit: setting the backgroundView to NULL causes those cells with text to, when they leave the view, come back without any background. So that isn't a viable solution. Also, the text for the detailTextLabel is still set on the cell that shouldn't have any text.
This is how it looks, with the cell backgroundViews set to nil and the text showing up on the delete cell where it shouldn't:
Solution, as recommended by Alex Deem (replacing old dequeue code with this code):
NSString* identifier;
if(indexPath.section == 0)
identifier = #"0";
else
identifier = #"1";
UISwitch *switchView;
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier];
if (cell == nil) {
// No cell to reuse => create a new one
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:identifier] autorelease];
You should read the documentation regarding the reuse of cells.
You should be using a different reuseIdentifier for each of the two sections, since they are fundamentally differently styled cells.
add a closing } bracket to these lines of code:
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"blahblahblah"];
if (cell == nil) {
// No cell to reuse => create a new one
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:#"blahblahblah"] autorelease];
}
....
....
....
if(indexPath.section == 1) {
....
....
}
if(indexPath.section == 0) {
....
....
}
and I suspect you will have better results in your table.
The way things are working right now (at least as far as I can tell in your code), you create one cell and it gets initialized to something. It never gets reset to the values & data of anything else that's being requested.
Your code is structured wrong.
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"blahblahblah"];
if (cell == nil)
dqueueReuseableCellWithIdentifier will return an existing previously created cell if it is no longer in use. If cell == nil you should create a new cell and set defaults common to all cells. However any setting of data unique to that indexPath should be done after the
if(cell==nil) block.
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"blahblahblah"];
if (cell == nil)
{
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:#"blahblahblah"] autorelease];
}
cell.textLabel.text=#"unique text";
return cell;
Related
when I set UITableViewCellSeparatorStyleNone to a tableView, still the separatorview is visble?
I set the property of tableview,
self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
and in view debug I still found a UITableViewCellSeparatorView in my cell,
How do I remove the separator view?
You can set UITableViewCellSeparatorStyleNone in tableview in storyboard.
Here i attach screenshot for more clarification.
since cells are being reused when presented (with dequeueReusableCellWithIdentifier): you have to use a different identifier for that cell.. I made a custom UITableViewCell subclass for it too.
this is a code where my last cell is a special cell that will load X more cells..
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
if (indexPath.row == lastIndex) {
LoadingNextCellView *cell = [tableView dequeueReusableCellWithIdentifier:#"LoadingNextCell"];
if (cell == nil) {
cell = [[LoadingNextCellView alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"LoadingNextCell"];
}
cell.indexPath = indexPath;
cell.titleLabel.text = [NSString stringWithFormat:#"Loading next %d trees..",PRELOAD_TREES];
return cell;
} else {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"Cell"];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"Cell"];
}
}
return cell;
}
Customie your cell according to this logic.
This question already has answers here:
How to remove arrow in UITableView
(6 answers)
Closed 8 years ago.
I'm having a problem with this. What I did was every cell in indexPath.row % 2 == 1 I want to set it to blank so there could be a margin. But now it looks like this:
I want to remove the ">" in the cell that serves as a margin. How to remove that and remove the highlight thing when pressed? When pressed it turns to grey.
And how to delete the cell with this logic since every row is in odd numbers but the actual object is still in their proper indexes.
Here's my code:
if (indexPath.row % 2 == 1) {
UITableViewCell *cell2 = [tableView dequeueReusableCellWithIdentifier:CELL_ID2];
if (cell2 == nil) {
cell2 = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CELL_ID2];
[cell2.contentView setAlpha:0];
cell2.selectionStyle = UITableViewCellSelectionStyleNone;
cell2.userInteractionEnabled = NO;
}
return cell2;
}
Just set cell2.accessoryType = UITableViewCellAccessoryNone;
You're pretty close:
if (indexPath.row % 2 == 1) {
UITableViewCell *cell2 = [tableView dequeueReusableCellWithIdentifier:CELL_ID2];
if (cell2 == nil) {
cell2 = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CELL_ID2];
}
cell2.selectionStyle = UITableViewCellSelectionStyleNone;
cell2.accessoryType = UITableViewCellAccessoryNone;
return cell2;
}
Your cell configuration (if cell is nil) should contain the bare minimum of what you need because the cells get reused (dequeueReusableCellWithIdentifier:). So you need to configure every indepedant part of the cell when it is reused. Thus you need to set the properties you need for that row of the indexPath.
You will need to set the accessaryType to UITableViewCellAccessoryNone
cell2.accessoryType = UITableViewCellAcessoryNone;
https://developer.apple.com/library/ios/documentation/uikit/reference/UITableViewCell_Class/Reference/Reference.html#//apple_ref/doc/c_ref/UITableViewCellAccessoryType
I have 2 tableViews, the first only loads a list from an array.
The other 1, show details per row. But it shows a crash report:
'UITableView dataSource must return a cell from tableView:cellForRowAtIndexPath: Exception'
What seems to be wrong with my code? I want to show each row a different detail that came from the same sqlite row.
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell;
//tableView 1
if(tableView == self.cTableLabel)
{
cell = [tableView dequeueReusableCellWithIdentifier:#"courseCell"];
NSLog(#"Here.");
Course *courses = [self.course objectAtIndex:indexPath.row];
cell.textLabel.text =courses.cName;
cell.detailTextLabel.text =courses.cSchool;
return cell;
}
//tableView 2
if(tableView == self.jTableLabel)
{
if (indexPath.row == 0)
{
cell = [tableView dequeueReusableCellWithIdentifier:#"JobName"];
cell.textLabel.text = _jDetails.jName;
}
else if (indexPath.row == 1)
{
cell= [tableView dequeueReusableCellWithIdentifier:#"JobEarnings"];
cell.textLabel.text = #"Job Earnings (per month): Php";
cell.detailTextLabel.text = _jDetails.jEarnings;
}
return cell;
}
return 0;
}
For performance reasons, a table view's data source should generally reuse UITableViewCell objects when it assigns cells to rows in its tableView:cellForRowAtIndexPath: method. A table view maintains a queue or list of UITableViewCell objects that the data source has marked for reuse. Call this method from your data source object when asked to provide a new cell for the table view. This method dequeues an existing cell if one is available or creates a new one using the class or nib file you previously registered. If no cell is available for reuse and you did not register a class or nib file, this method returns nil.
If you registered a class for the specified identifier and a new cell must be created, this method initializes the cell by calling its initWithStyle:reuseIdentifier: method. For nib-based cells, this method loads the cell object from the provided nib file. If an existing cell was available for reuse, this method calls the cell’s prepareForReuse method instead.
You need to create different cells for each tableview, Try to use the above code:
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell;
//tableView 1
if(tableView == self.cTableLabel)
{
cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
}
else
{
for(UIView *view in cell.contentView.subviews)
{
[view removeFromSuperview];
}
}
NSLog(#"Here.");
Course *courses = [self.course objectAtIndex:indexPath.row];
cell.textLabel.text =courses.cName;
cell.detailTextLabel.text =courses.cSchool;
return cell;
}
//tableView 2
if(tableView == self.jTableLabel)
{
cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
}
else
{
for(UIView *view in cell.contentView.subviews)
{
[view removeFromSuperview];
}
}
if (indexPath.row == 0)
{
cell = [tableView dequeueReusableCellWithIdentifier:#"JobName"];
cell.textLabel.text = _jDetails.jName;
}
else if (indexPath.row == 1)
{
cell= [tableView dequeueReusableCellWithIdentifier:#"JobEarnings"];
cell.textLabel.text = #"Job Earnings (per month): Php";
cell.detailTextLabel.text = _jDetails.jEarnings;
}
return cell;
}
return 0;
}
Please cross check either one of your table is returning more number of rows in numberOfRowsInSection method . It might be that you haven't put check on this method as both of the table are returning different number of rows .
First, check that your numberOfRowsInSection returns the correct number of rows for your table. I would think this would be it.
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
if(tableView == self.cTableLabel)
{
return [self.course count];
}
//tableView 2
if(tableView == self.jTableLabel)
{
return 2;
}
return 0;
}
Otherwise I would set a break point on return 0; or NSLog before it in cellForRowAtIndexPath, because my guess is neither if block is hit and you are returning zero. Does it get triggered?
Edit - Ah, I think I see dequeueReusableCellWithIdentifier: will return a nil cell if you haven't set one up yet. Try using dequeueReusableCellWithIdentifier: forIndexPath: instead. This will always return a valid cell assuming you called registerClass:[UITableViewCell class] forCellReuseIdentifier: first.
Give this a shot:
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell;
[self.tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:#"courseCell"];
[self.tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:#"JobName"];
[self.tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:#"JobEarnings"];
//tableView 1
if(tableView == self.cTableLabel)
{
cell = [tableView dequeueReusableCellWithIdentifier:#"courseCell" forIndexPath:indexPath];
NSLog(#"Here.");
Course *courses = [self.course objectAtIndex:indexPath.row];
cell.textLabel.text =courses.cName;
cell.detailTextLabel.text =courses.cSchool;
return cell;
}
//tableView 2
if(tableView == self.jTableLabel)
{
if (indexPath.row == 0)
{
cell = [tableView dequeueReusableCellWithIdentifier:#"JobName" forIndexPath:indexPath];
cell.textLabel.text = _jDetails.jName;
}
else if (indexPath.row == 1)
{
cell= [tableView dequeueReusableCellWithIdentifier:#"JobEarnings" forIndexPath:indexPath];
cell.textLabel.text = #"Job Earnings (per month): Php";
cell.detailTextLabel.text = _jDetails.jEarnings;
}
return cell;
}
return 0;
}
Also registerClass:[UITableViewCell class] forCellReuseIdentifier: could be called in your init, it only needs to be declared once.
I am using UITableView with group-type, and I am adding different content on UITableViewCell
and each indexPath.section I am checking in UITableViewCell delegate method
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
cellIdentifier = (indexPath.row % 2 == 0 ? #"EvenCell" : #"OddCell");
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle: UITableViewCellStyleDefault
reuseIdentifier:cellIdentifier];
if (indexPath.section == 0)
{
// adding image
// called
}
else if (indexPath.section == 1)
{
// adding lable
called
}
else if (indexPath.section == 2)
{
// adding panorma gps
called
}
else if (indexPath.section == 3)
{
not called // this section problem
}
else if (indexPath.section == 4)
{
not called // this section problem
}
}
return cell;
}
I have given number of section 5, but it is calling only indexPath.section 0, 1, and 2 only.
The problem is that that you only have only two types of cellIdentifier values (i.e. two types of cells you're reusing), but you appear to have five different layouts. The problem is that layouts are only called if a reused cell was not found. Thus, by the time you get down to section 3, dequeueReusableCellWithIdentifier is probably succeeding and reusing a cell that has scrolled off screen, and thus your code inside the if (cell == nil) block is not getting called at all for sections 3 and 4.
You can remedy that by either having more cell types, unique to the section number, too, e.g.:
NSString *cellType = (indexPath.row % 2 == 0 ? #"EvenCell" : #"OddCell");
NSString *cellIdentifier = [NSString stringWithFormat:#"%#-%d", cellType, indexPath.section];
You haven't shared what the even/odd logic is used for, so I'm not entirely sure what that's needed for. Assuming it's for something simple like backgroundColor, then I might be inclined to drop even/odd from the cellIdentifier altogether (and move the setting the background color outside the if (cell==nil) block), and just use the section number for the cell identifier:
NSString *cellIdentifier = [NSString stringWithFormat:#"MyCellSection-%d", indexPath.section];
We'd need a better sense of how different the various cells are configured (what is the degree of commonality) to make concrete suggestions on the best way to format this. But the key issue is that your cellIdentifier choices have to correspond to what's inside the if (cell == nil) block.
make sure you are returning 5 from here
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 5;
}
You call a method to the number of sections as follows?
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return 5;
}
Try call your methods after if(cell == nil):
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle: UITableViewCellStyleDefault
reuseIdentifier:cellIdentifier];
}
if (indexPath.section == 0) {
// adding image
// called
}
else if (indexPath.section == 1) {
// adding lable
called
}
else if (indexPath.section == 2) {
// adding panorma gps
called
}
else if (indexPath.section == 3) {
not called // this section problem
}
else if (indexPath.section == 4) {
not called // this section problem
}
I am trying to populate cells in table view ( I have two custom types of cells with with different elements created in storyboard, with identifiers "info_cell" and "person_cell", on segmented control above UITableView I decide what to load [tableView reload]). When I try to access UILabels inside cell I get that labels are null.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
NSString *CellIdentifier = (viewType == INFO_VIEW) ? #"info_cell" :#"person_cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
if(viewType == INFO_VIEW){
NSLog(#"INFO = %#", info_text_some_string);
UILabel *lblInfo = (UILabel *)[cell viewWithTag:200];
[lblInfo setText:info_text_some_string];
}
else{
// there is part for person
}
return cell;
}
Same code works when I have just one prototype cell inside table (UITableView is inside UIVewController). What can be problem here, I have checked 100 times: cell identifiers are OK, label tag is 200.
This is action for UISegmentControl
- (IBAction)changeView:(id)sender {
UISegmentedControl *segmentedControl = (UISegmentedControl *) sender;
NSInteger selectedSegment = segmentedControl.selectedSegmentIndex;
if (selectedSegment == 0) {
viewType = INFO_VIEW;
}
else{
viewType = PERSON_VIEW;
}
[tableView reloadData];
}
I have added and necessary methods for tableView and connect delegate i datasource.
Does anyone have any idea why it is null ?
Try this usually i follow this process whenever i go with custom cell in CellRorRowAtIndexPath
if(!cell)
{
cell =[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifier];
//customcell is your UITableViewCell created by you in ur xib
NSData *archivedData =[NSKeyedArchiver archivedDataWithRootObject:customcell];
cell =[NSKeyedUnarchiver unarchiveObjectWithData:archivedData];
}
if(viewType ==INFO_VIEW)
{
[(UILabel *)[cell viewWithTag:200] setText:#"you text"];
}
else{
// person view....
}
This way your collecting all your elements of your cell and setting value for it. share your results please
Assuming that you have subclass your UITableViewCells correctly (I use InfoCell and PersonCell for example), you can try this:
if(viewType == INFO_VIEW)
{
InfoCell *cell = (InfoCell *)[tableView dequeueReusableCellWithIdentifier:#"info_cell"];
// do your stuff for info here
}
else if(viewType == PERSON_VIEW)
{
PersonCell *cell = (PersonCell *)[tableView dequeueReusableCellWithIdentifier:#"person_cell"];
// do your stuff for person here
}
Why not do something like this?
[[cell textLabel] setText: #"text goes here"];
And skip the UILabel part?