on my tableview i have the last cell that is not initially visible as seen in the first image, when i scroll the list up, you can see in the second image that the price or my detailTextLabel is put on a new line not maintaining the right justification.
image 1 http://img706.imageshack.us/img706/4496/iphoneerror1.jpg
image 2 http://img706.imageshack.us/img706/6007/iphoneerror2edited.jpg
Here is the code, i can't figure out why its doing this, any direction or help would be much appreciated
- (UITableViewCell *)tableView:(UITableView *)ltableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [ltableView dequeueReusableCellWithIdentifier:CellIdentifier];
// Configure the cell.
NSUInteger indexRow = [indexPath row];
switch (indexRow) {
case 0:{
NSCharacterSet *set = [NSCharacterSet whitespaceCharacterSet];
NSString *description = [[currentData objectForKey:#"Description"] stringByTrimmingCharactersInSet:set];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier] autorelease];
}
cell.selectionStyle = UITableViewCellSelectionStyleNone;
cell.accessoryType = UITableViewCellAccessoryNone;
cellShift = 1;
if (![description isEqualToString:#""]) {
cell.textLabel.text = #"";
cell.detailTextLabel.text = description;
cell.detailTextLabel.numberOfLines = 2;
}
else {
cell.textLabel.text = #"";
cell.detailTextLabel.text = #"";
cell.detailTextLabel.numberOfLines = 0;
}
break;
}
default:{
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:CellIdentifier] autorelease];
}
NSDictionary *item = [tableData objectAtIndex:(indexRow-cellShift)];
NSString *name = [item objectForKey:#"Name"];
if ([name length] > MaxVendorsLength ) {
name = [NSString stringWithFormat:#"%# ...",[name substringToIndex:MaxVendorsLength]];
}
cell.textLabel.text = name;
cell.textLabel.minimumFontSize = 12;
NSString *priceString;
float price = [[item objectForKey:#"Price"] floatValue];
//NSLog(#"| %# | : | %# |",[item objectForKey:#"Name"], [item objectForKey:#"Price"]);
if (price != 0) {
priceString = [[NSString alloc] initWithFormat:#"$%.2f",price];
}
else {
priceString = [[NSString alloc] initWithString:#"--"];
}
cell.detailTextLabel.text = priceString;
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
[priceString release];
break;
}
}
cell.textLabel.font = [UIFont boldSystemFontOfSize:15];
cell.textLabel.minimumFontSize = 14;
cell.detailTextLabel.font = [UIFont boldSystemFontOfSize:15];
cell.detailTextLabel.minimumFontSize = 14;
return cell;
}
Let me know if i need to post anything else to get help with this ???
It's because when you scroll up the top cell is reused because all of your cells have the same cell identifier (the first line you have). You need to declare the two cell identifiers and use the appropriate one based on what row you're trying to get.
static NSString *FirstRowCellIdentifier = #"A";
static NSString *OtherRowCellIdentifier = #"B";
NSString *cellIdentifier = nil;
if ([indexPath row] == 0)
cellIdentifier = FirstRowCellIdentifier;
else
cellIdentifer = OtherRowCellIdentifier;
UITableViewCell *cell = [ltableView dequeueReusableCellWithIdentifier:cellIdentifier];
// .....
Then you can use the rest of your code as is. This just ensures that the resused cell is of the correct type.
You're using the same cell identifier for all rows but the 0th row has a different style. When scrolling up, a subtitle-styled cell might be getting re-used.
Try using a different cell identifier for the 0th row. Keep just the declaration of cell outside the switch and move the dequeueReusableCellWithIdentifier to each case.
(UITableViewCell *)tableView:(UITableView *)ltableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
Related
I have a grouped UITableView that I populate from a list.
On some rows I don't want to have disclosure and on some I need to add label.
But is somehow mix something and add labels on wrong rows and display disclosures at each row.
What am I doing wrong here?
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if(cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:CellIdentifier];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
cell.accessoryView = [[ UIImageView alloc ]
initWithImage:[UIImage imageNamed:#"customdisclosure.png" ]];
}
NSDictionary *dictionary = [_list objectAtIndex:indexPath.section];
NSArray *array = [dictionary objectForKey:#"Items"];
NSString *cellValue = [array objectAtIndex:indexPath.row];
cell.textLabel.text = cellValue;
if([cell.textLabel.text isEqualToString:#"with label"])
{
cell.accessoryType = UITableViewCellAccessoryNone;
cell.detailTextLabel.textColor = [UIColor blackColor];
cell.detailTextLabel.text = #"label...";
cell.selectionStyle = UITableViewCellSelectionStyleNone;
}
else if([cell.textLabel.text isEqualToString: #"No disclosure" ])
{
cell.accessoryType = UITableViewCellAccessoryNone;
}
return cell;
}
in your else if clause, you are not clearing the cell.detailTextLabel's text on the reused cell. Set it to nil and you will be fine.
cell.detailTextLabel.text = nil;
You will also need to hide the accessoryView in the else if clause, and unhide it.
cell.accessoryView.hidden = YES;
Overall, I would consider subclassing UITableViewCell so you can override prepareForReuse to reset your cell for the next cellForRowAtIndexPath call.
Guess the issue is with using reusable identifiers. Use different cell identifiers for the cells you do not want accessoryView.
static NSString *CellWithDisclosure = #"CellID_WithDisclosure";
static NSString *CellWithNoDisclosure = #"CellID_NoDisclosure";
NSDictionary *dictionary = [_list objectAtIndex:indexPath.section];
NSArray *array = [dictionary objectForKey:#"Items"];
NSString *cellValue = [array objectAtIndex:indexPath.row];
if([cell.textLabel.text isEqualToString:#"with label"])
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellWithDisclosure];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
}
else if([cell.textLabel.text isEqualToString: #"No disclosure" ])
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellWithNoDisclosure];
cell.accessoryType = UITableViewCellAccessoryNone;
}
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:cellID] autorelease];
}
cell.textLabel.text = cellValue;
return cell;
I have a UItableview with 10 cells.I need to display a message from an NSarray into this tableview.The array contains 3 items and needs to be displayed in the any of the 3 cells .
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
CustomTableView *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[ CustomTableView alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:nil];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
}
NSString *order = [orderArray objectAtIndex:indexPath.row];
NSString *sdate = [dateArray objectAtIndex:indexPath.row];
//Label positions
UILabel *ordernum = [[UILabel alloc] initWithFrame:CGRectMake(5,28,95,21)];
UILabel *date = [[UILabel alloc] initWithFrame:CGRectMake(100,28,80,21)];
UILabel *orderStatusMessage = [[UILabel alloc] initWithFrame:CGRectMake(200,28,80,21)];
NSString *ordertypeName = [ordertypeArray objectAtIndex:indexPath.row];
ordernum.textColor = [UIColor blackColor];
[cell.contentView addSubview:ordernum];
date.textColor = [UIColor blackColor];
[cell.contentView addSubview:date];
orderStatusMessage.textColor = [UIColor blackColor];
if ([ordertypeName isEqualToString:#"saved"]) {
ordernum.text = [NSString stringWithString:#"Saved Order"];
date.text = [NSString stringWithFormat:#"%#",sdate];
}
else{
if (![order isEqualToString:#""]) {
for (int i=0; i<[reversed count]; i++)
{
stat=[reversed objectAtIndex:i];
}
}
ordernum.text = [NSString stringWithFormat:#"%#",order];
date.text = [NSString stringWithFormat:#"%#",sdate];
orderStatusMessage.text =[NSString stringWithFormat:#"%#",stat];
[cell.contentView addSubview:orderStatusMessage];
}
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
cell.selectionStyle = UITableViewCellSelectionStyleGray;
// }
return cell;
}
With the above code I am getting only the last item from reversed array.Please help
To start, your for loop is bogus
if (![order isEqualToString:#""]) {
for (int i=0; i<[reversed count]; i++)
{
stat=[reversed objectAtIndex:i];
}
}
Why are you looping and overwriting the reference to stat with each iteration? That's clearly not your intent.
Second, I would advise refactoring, since this code snippit is extremely confusing and it is very close to impossible to understand the intent. Please repost after renaming variables and cleaning the code a bit.
In my UITableView, I want to show loading indicator in the last cell.
For remaining cells, I created a custom table view cell which is working fine. But when I scroll to the end, its crashing and not able to load loading indictor (which is a different custom cell view). Here's my code.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"HomeViewCell";
UITableViewCell* cellToReturn = nil;
// Configure the cell.
NSInteger row = [indexPath row];
if (row < [jokesTableArray count])
{
CustomTableCell* cell = (CustomTableCell*)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
cell = [[[CustomTableCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
}
NSDictionary* dict = [jokesTableArray objectAtIndex:indexPath.row];
NSNumber* rating = [[ServerCommunicator getInstance] getCurrentUserJokeRating:[dict objectForKey:#"id"]];
cell.userRatedTheJoke = rating != nil ? YES : NO;
cell.titleLabel.text = [dict objectForKey:#"title"];
cell.descriptionLabel.text = [dict objectForKey:#"text"];
cell.upVotes.text = [NSString stringWithFormat:#"%2.2f",[[dict objectForKey:#"rating_count"] floatValue]];
[cell setRating:rating != nil ? [rating intValue] : [[dict objectForKey:#"rating_count"] intValue]];
NSString* authorName = [dict objectForKey:#"author"];
if (authorName != nil && ![authorName isEqual:[NSNull null]])
{
cell.author.text = [NSString stringWithFormat:#"By:%#",authorName];
}
cellToReturn = cell;
}
else
{
KMLoadingIndicatorCell* cell = (KMLoadingIndicatorCell*)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
KMLoadingIndicatorCell* cell = [[[KMLoadingIndicatorCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
cell.loadingLabel.text = #"Loading...";
cellToReturn = cell;
}
}
return cellToReturn;
}
Since you are using the same reuseIdentifier, the line
KMLoadingIndicatorCell* cell = (KMLoadingIndicatorCell*)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
is most likely setting cell to an instance of CustomTableCell that is now being reused, rather than the expected KMLoadingIndicatorCell. You should be using different identifiers for the two different types of cells.
You should use a different Cell Identifier for your custom cell.
I know there's similar questions to this, but the approved answers don't seem to be working for me. So, my scenario is that I have a UITableView and I want to add and remove items by scanning a bar code. All that works fine except I can't get the UITableView to display the updated information. The problem specifically comes from the tableView:cellForRowAtIndexPath: method on every other reload after the initial one. More specifically the cell is always not nil, so it skips over the new cell creation logic.
For other questions like mine, the answer is that the cell identifier is the problem. Well, I tried messing around with that and it didn't work. Here's my code:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = nil;
if (indexPath.section < vehicle.inventoryCategoriesCount) {
cell = [tableView dequeueReusableCellWithIdentifier:#"ModelCell"];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:#"ModelCell"] autorelease];
NSString *model = [[[vehicle.inventory filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:#"category == %#", [vehicle.inventoryCategories objectAtIndex:indexPath.section]]] valueForKeyPath:#"#distinctUnionOfObjects.model"] objectAtIndex:indexPath.row];
cell.textLabel.text = model;
cell.detailTextLabel.text = [NSString stringWithFormat:#"%d", [[vehicle.inventory filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:#"model == %#", model]] count]];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
}
} else {
cell = [tableView dequeueReusableCellWithIdentifier:#"RemoveCell"];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"RemoveCell"] autorelease];
cell.textLabel.text = #"Remove an Item";
cell.textLabel.textColor = [UIColor redColor];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
}
}
return cell;
}
So, in this example code, I have two different cell identifiers for the separate sections. They are ModelCell and RemoveCell. Well, they don't work as a solution because nothing happens. If I change the cell identifier when I'm allocating a new cell it works because it's simply wiping everything since the identifiers don't match, but I'm going to assume that that is wrong and that there should be a better solution to this issue or I'm simply not doing something right.
I'd appreciate some help on this. I've spent a day on this chunk of code so far and I have not gotten anywhere and I'd like to get it fixed and move on to other part of my app...
Thanks in advance for any help!
UPDATE
Thanks to #fluchtpunkt the problem has been resolved. For anyone else who may run into this in the future, here's the corrected code. I decided to make the identifier even more unique by appending the section number to it.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = nil;
if (indexPath.section < vehicle.inventoryCategoriesCount) {
NSString *identifier = [NSString stringWithFormat:#"ModelCell-%d", indexPath.section];
cell = [tableView dequeueReusableCellWithIdentifier:identifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:identifier] autorelease];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
}
NSString *model = [[[vehicle.inventory filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:#"category == %#", [vehicle.inventoryCategories objectAtIndex:indexPath.section]]] valueForKeyPath:#"#distinctUnionOfObjects.model"] objectAtIndex:indexPath.row];
cell.textLabel.text = model;
cell.detailTextLabel.text = [NSString stringWithFormat:#"%d", [[vehicle.inventory filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:#"model == %#", model]] count]];
} else {
cell = [tableView dequeueReusableCellWithIdentifier:#"RemoveCell"];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"RemoveCell"] autorelease];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
cell.textLabel.textColor = [UIColor redColor];
}
cell.textLabel.text = #"Remove an Item";
}
return cell;
}
UPDATE
The final code version which corrects my misunderstanding of how the identifier works. I figured I'd keep it simple, so I named the identifiers after the cell style type.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = nil;
if (indexPath.section < vehicle.inventoryCategoriesCount) {
cell = [tableView dequeueReusableCellWithIdentifier:#"Value1"];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:#"Value1"] autorelease];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
}
NSString *model = [[[vehicle.inventory filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:#"category == %#", [vehicle.inventoryCategories objectAtIndex:indexPath.section]]] valueForKeyPath:#"#distinctUnionOfObjects.model"] objectAtIndex:indexPath.row];
cell.textLabel.text = model;
cell.detailTextLabel.text = [NSString stringWithFormat:#"%d", [[vehicle.inventory filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:#"model == %#", model]] count]];
} else {
cell = [tableView dequeueReusableCellWithIdentifier:#"Default"];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"Default"] autorelease];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
cell.textLabel.textColor = [UIColor redColor];
}
cell.textLabel.text = #"Remove an Item";
}
return cell;
}
put your cell configuration outside of if (cell == nil) { ... } The if condition is only true if no cell could be reused. And you definitely want to reuse your cells. So configure them when you have a valid cell.
Like this:
if (indexPath.section < vehicle.inventoryCategoriesCount) {
cell = [tableView dequeueReusableCellWithIdentifier:#"ModelCell"];
if (cell == nil) {
// only create a new cell if a dequeue was not successful.
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:#"ModelCell"] autorelease];
}
// whatever happened before you have a valid cell here.
// configure cell:
NSString *model = [[[vehicle.inventory filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:#"category == %#", [vehicle.inventoryCategories objectAtIndex:indexPath.section]]] valueForKeyPath:#"#distinctUnionOfObjects.model"] objectAtIndex:indexPath.row];
cell.textLabel.text = model;
cell.detailTextLabel.text = [NSString stringWithFormat:#"%d", [[vehicle.inventory filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:#"model == %#", model]] count]];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
}
if you want to optimize your code you could move the options that are the same for every cell inside the (cell == nil) condition. For example setting the selectionStyle, or changing the textcolor
Alex - if I look at your code right at the top, you're doing this:
cell = [tableView dequeueReusableCellWithIdentifier:#"ModelCell"];
However, all the examples (and my code) require a static NSString for the CellIdentifier
static NSString *MyIdentifier = #"MyIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:MyIdentifier];
This then works the intended way.
You definitely reuse your cells . if you put your configuration inside if(cell == nil) , it works when no cell is reused . so please put the following code snippet outside of if(cell == nil) condition------------
if(cell == nil)
{``
// enter code here
}
NSString *model = [[[vehicle.inventory filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:#"category == %#", [vehicle.inventoryCategories objectAtIndex:indexPath.section]]] valueForKeyPath:#"#distinctUnionOfObjects.model"] objectAtIndex:indexPath.row];
cell.textLabel.text = model;
cell.detailTextLabel.text = [NSString stringWithFormat:#"%d", [[vehicle.inventory filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:#"model == %#", model]] count]];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
i have a UITableViewCell loading 10 images its loads the first 6, then its saying (cell != nil) so it doesnt load the remaining images, but if i remove the "if(cell==nil)" it loads all the images
am i missing something?
thanks
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
AsyncImageView *asyncImageView = nil;
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
int section = indexPath.section;
NSMutableArray *sectionItems = [sections objectAtIndex:section];
if (cell == nil) {
NSLog(#"CELL == NIL %#", cell);
int n = ([sectionItems count]) ;
cell = [[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
cell.accessoryType = UITableViewCellAccessoryNone;
cell.selectionStyle = UITableViewCellSelectionStyleNone;
int i=0,f=0;
while (i < n)
{
int yy = 4 +f*74;
for(int j=0; j<3;j++){
Item *item = [sectionItems objectAtIndex:i];
int buttonX = 10;
if (i == 0) {
buttonX = 10;
}else {
buttonX = 203
}
CGRect frame;
frame.origin.x = buttonX;
frame.origin.y = yy;
frame.size.width = 107;
frame.size.height = 107;
asyncImageView = [[[AsyncImageView alloc] initWithFrame:frame] autorelease];
asyncImageView.tag = ASYNC_IMAGE_TAG;
NSString *urlString = item.image;
NSURL *url = [NSURL URLWithString:urlString];
[asyncImageView loadImageFromURL:url];
[cell.contentView addSubview:asyncImageView];
i++;
}
f = f+1;
}
}
else {
NSLog(#"cell != nill");
asyncImageView = (AsyncImageView *) [cell.contentView viewWithTag:ASYNC_IMAGE_TAG];
}
return cell;
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
NSLog(#"CELL == NIL %#", cell);
cell = [[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
cell.accessoryType = UITableViewCellAccessoryNone;
cell.selectionStyle = UITableViewCellSelectionStyleNone;
CGRect frame = CGRectMake(0,20,30,40);
UIImageView *img = [[[UIImageView alloc] initWithFrame:frame];
img.tag = IMAGE_TAG;
[cell.contentView addSubview:img];
[img release];
}int row = indexPath.row;
UIImageView *myImage = = (UIImageView *) [cell.contentView viewWithTag:IMAGE_TAG];
UIImage *image = [UIImage imageNamed:[NSString stringWithFormat:#"%d" , row]];
[myImage setImage:image];
return cell;}
UITableViewCells are cached to save memory and allocations costs (hence performance). You only create a cell once and after that you set it contents based on your index path. I've simply created an imageview in the cell and later on set an image depending on the indexpath in that cell (1.png , 2.png etc).
Read the documentation here.
UITableViewCells are re-used to save time and memory, typically, and you're using this paradigm I see. You need to implement the cell != nil case and set up the cell to display the contents based on the indexPath. The cell was previously used to display other content so you need to adjust all indexPath-dependent views in the non-nil cell.