cell labels are not refreshing in table - iphone

I am attempting to call a reloadData on my table's rows on a viewDidAppear method access. However, my cells are not refreshing their values and I cannot figure out why, as it seems everything is being accessed in the order it is suppose to. To make matters more odd, 1 row actually does refresh, but none of the others do.
Here is my code...
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
// Set up the cell...
static NSString *CellWithIdentifier = #"Cell";
UITableViewCell *cell = (UITableViewCell *)[tableView dequeueReusableCellWithIdentifier:CellWithIdentifier];
NSLog(#"generating cell contents");
if (cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellWithIdentifier];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
cell.textLabel.text = [_tableGroup.options objectAtIndex:rowcount];
rowcount++;
//label for currently selected/saved setting
_currentSetting = [[UILabel alloc] initWithFrame:CGRectMake(160, 8, 115, 25)];
[_currentSetting setFont:[UIFont systemFontOfSize:14]];
_currentSetting.backgroundColor = [UIColor clearColor];
_currentSetting.textColor = [UIColor blueColor];
_currentSetting.textAlignment = NSTextAlignmentRight;
[cell.contentView addSubview:_currentSetting];
NSLog(#"added new label to cell");
}
//depending on the setting, set the label in the cell to what is currently selected
if (indexPath.section == 1 && indexPath.row == 0) {
_currentSetting.text = [NSString stringWithFormat:#"%# %#",[settings.mapDistance stringValue], NSLocalizedString(#"MILES_IDENTIFIER", nil)];
NSLog(#"setting map distance label: %#", settings.mapDistance);
}
else if(indexPath.section == 1 && indexPath.row == 1)
{
_currentSetting.text = [NSString stringWithFormat:#"%# %#",[settings.maxCustomers stringValue], NSLocalizedString(#"ITEMS_IDENTIFIER", nil)];
NSLog(#"setting max customers: %#", settings.maxCustomers);
}
else if(indexPath.section == 2)
{
_currentSetting.text = [NSString stringWithFormat:#"%# %#",[settings.maxProducts stringValue], NSLocalizedString(#"ITEMS_IDENTIFIER", nil)];
NSLog(#"setting max products: %#", settings.maxProducts);
}
return cell;
}
based on this code, i get this output with my NSLOGS.
this is the first run of the cells when the view is created. It generates 4 cells, puts labels in each cell, and in 3 of those labels, puts in a value.
generating cell contents
added new label to cell
generating cell contents
added new label to cell
setting map distance: 15
generating cell contents
added new label to cell
setting max customers: 250
generating cell contents
added new label to cell
setting max products: 150
at this point i have clicked a row, went to a different screen, and have now returned. as you can see, map distance is different. although no change is displayed, even though the code to change the label's text is accessed during the reload process.
reloading data
generating cell contents
generating cell contents
setting map distance: 25
generating cell contents
setting max customers: 250
generating cell contents
setting max products: 150
again, I'm at a loss because the last row DOES refresh correctly. But none of the others do.
Thanks

When you reload your tableView, the cells already exist and are dequeued from the tableView, so the condition if (cell == nil) returns false, and the cell creation code is not executed.
In that cell creation code, you are assigning a value to _currentSetting and then proceed with the acode assuming that value is correct. However, when the cell creation code is not executed, that value points to the latest created cell, and thus, it won't update.
To fix this: make _currentSetting a local variable and change the code to look like this:
(You don't really need to make it a local variable, but it's more appropriate because you don't really need a reference to the last label you created after you leave this method)
UILabel *_currentSetting = nil;
if (cell == nil) {
_currentSetting = ...
_currentSetting.tag = 123;
}
else
_currentSetting = [cell.contentView viewWithTag:123];
...

The problem here is that the second time (when you are reloading the view ) the _currentSetting is not having a valid memory .So it is better to implement a custom cell and do the job
Better refer this an excellent guide

The second time around, you can see that "added new label to cell" isn't being called, so you're re-using an old tableViewCell.
Note that you're not setting _currentSetting when re-using a cell, only when creating a new cell. So _currentSetting is set to the last new cell that was created, most likely the last cell in the table.
You need to make sure to set _currentSetting to the correct label (maybe by using viewWithTag: or something similar).
(e:f;b)

Related

Removing a checkmark accessory that is placed by default in my TableView

Brand new poster here on StackOverflow. I've been reading and learning here for some time, but I need to start asking a few questions and interacting, so any help with a few of my issues would be greatly appreciated.
I basically generate a list in a tableView of default sounds from a plist in cellForRowAtIndexPath. This generates me a list of say "x" sounds and one of those sounds has a default checkmark accessory placed on its cell. I have a plist file that stores the 'active' sound file's index value, this is how I put the original checkmark in the generated tableView. So, in the code below, as you can see, I load in the plist's value for the 'active' sounds index, however, when a user interacts with my tableView and they select a new sound, I need the default checkmark placed to be removed from view. Everything else is working fine. I can't seem to crack this simple problem, Im sure its a simple syntax issue, i just don't know how to get it done. Im sure the solution is a single line of code or two and its right under my nose. Thank you for help in advance.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSDictionary *dictionarySound = [NSDictionary dictionaryWithContentsOfFile:[self ActDataFilePath]];
NSNumber *defaultSoundIndex = [dictionarySound valueForKey:#"soundIndex"];
int theIntVal = [defaultSoundIndex integerValue];
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
//Everything below works just fine, checkmarks are removed and placed accordingly, sounds are played just fine. I just need help above in removing the default checkmark
if(self.checkedPath)
{
UITableViewCell *uncheckCell = [tableView cellForRowAtIndexPath:self.checkedPath];
uncheckCell.accessoryType = UITableViewCellAccessoryNone;
}
cell.accessoryType = UITableViewCellAccessoryCheckmark;
self.checkedPath = indexPath;
....... other code below the plays my sounds on click and stores the newly active sound name and index value in the plist.
The usual way of dealing with this is to use didSelectRowAtIndexPath: to record the fact that the selection has changed and tell the table view to reload data, either all or just for the affected cells, then do the accessoryType configuration in cellAtRowForIndexPath:.
Other ways tend to fail if scrolling of the table is possible.
Alright boys and girls, here is the solution to my own question.
The checkmark is determined and placed in cellForRowAtIndexPath initially when the table is built based on my plist file. Here is the code for my cellForRowAtIndexPath that grabs my plist data, builds my table and sets the default selection with a checkmark.
NSDictionary *dicSound = [NSDictionary dictionaryWithContentsOfFile:[self ActDataFilePath]];
NSNumber *defaultSoundIndex = [dicSound valueForKey:#"soundIndex"];
//conversion of NSNumber to integer for comparison below to indexPath.row, both need to be int's
int theIntVal = [defaultSoundIndex integerValue];
static NSString *CheckMarkCellIdentifier = #"CheckMarkCellIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier: CheckMarkCellIdentifier];
cell.textLabel.text = [[MyArray objectAtIndex:indexPath.row] objectForKey:#"name"];
if(indexPath.row == theIntVal)
{
cell.accessoryType = UITableViewCellAccessoryCheckmark;
}
else
{
cell.accessoryType = UITableViewCellAccessoryNone;
}
return cell;
When the user interacts with the tableView by clicking on another cell and didSelectRowAtIndexPath kicks in, this is how Im placing the new checkmark and how Im setting the old cell to have no accessory checkmark.
//This is a dictionary file that contains a number of values I need to grab
NSDictionary *dictionarySound = [NSDictionary dictionaryWithContentsOfFile:[self ActDataFilePath]];
NSNumber *defaultSoundIndex = [dictionarySound valueForKey:#"soundIndex"];
//conversion of NSNumber to integer for comparison below to indexPath.row, both need to be int's
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
if(self.checkedPath)
{
UITableViewCell *uncheckCell = [tableView cellForRowAtIndexPath:self.checkedPath];
uncheckCell.accessoryType = UITableViewCellAccessoryNone;
}
cell.accessoryType = UITableViewCellAccessoryCheckmark;
self.checkedPath = indexPath;
//THE FIX
[tableView reloadData];
The key here is the [tableView reloadData]; line as it reloads the table with the new options checked and removes the original checkmark. Obviously, Im reloading data which means that I have persistence built in in a plist file. I basically update the local dictionary's value for 'soundIndex' EVERY TIME a user clicks on a cell and then write that to the persistent plist file.
Hope this helps anyone else who is having this issue.
Try following code
cell.accessoryType = UITableViewCellAccessoryNone;

When an UITableView is empty, show an UIImage

This is related to another question of mine which wasn't answered in a helpful way (message when a UITableView is empty).
I'm trying to show an UIImage graphic that says You haven't saved any bookmarks over an UITableView when it's empty. I have NSNotification set-up so that when bookmarks are added or deleted, a message is sent so that the UITableView can be updated.
I've been trying to do it with this code. Why won't this work?
- (void)bookmarksChanged:(NSNotification*)notification
{
[self.tableView reloadData];
UIImageView* emptyBookmarks = [[UIImageView alloc] initWithFrame:CGRectMake(75, 100, 160, 57)];
emptyBookmarks.alpha = 1;
emptyBookmarks.image = [UIImage imageNamed:#"emptyBookmark.png"];
[self.view addSubview:emptyBookmarks];
[emptyBookmarks release];
if ([self.dataModel bookmarksCount] == 0)
{
emptyBookmarks.alpha = 1;
}
else
{
emptyBookmarks.alpha = 0;
}
}
I'm probably approaching this the wrong way... But if salvageable, what am I doing wrong?
When I initially have an empty bookmarks tableview, there's no image displayed. After I add a bookmark and then delete it, the image shows. Grrh.
Another way (and IMO the correct way) to do this is to manipulate the backgroundView property on the UITableView.
While making a single cell with a custom image cell would certainly works, I think it overly complicates the logic of your UITableViewController's data source. It feels like a kludge.
According to UITableView documentation:
A table view’s background view is automatically resized to match the
size of the table view. This view is placed as a subview of the table
view behind all cells , header views, and footer views.
Assigning an opaque view to this property obscures the background color
set on the table view itself.
While you probably don't want to just set it to your UIImageView, it is very easy to make a UIView that contains the UIImageView that you want.
Well first off if you were going to do it that way, you would need to reload the tableView after updating the image or model etc. and not before.
But you are probably making things more complicated than they need to be!
Why not just check to see if the data for section 0 and indexPath.row 0 are empty and if so in cellForRowAtIndexPath display a text message accordingly.
// First make sure there is always one row returned even if the dataModel is empty.
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
NSInteger numRows = 0;
if ([self.dataModel lastObject]) {
// Return the number of rows in the section.
numRows = [self.dataModel count]; // etc.
}
if (numRows < 1) numRows = 1;
return numRows;
}
// Then display the data if there is some, otherwise a message if empty.
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
}
if ([self.dataModel lastObject]) {
// setup the cell the normal way here.
} else { // the datasource is empty - print a message
cell.textLabel.text = nil;
cell.detailTextLabel.text = NSLocalizedString(#"You haven't saved any bookmarks", #"");
cell.detailTextLabel.textColor = [UIColor colorWithRed:0/255.0 green:0/255.0 blue:0/255.0 alpha:0.7];
cell.accessoryType = UITableViewCellAccessoryNone;
}
return cell;
}
Are you sure [self.dataModel bookmarksCount] is equal to 0 ?
While I agree that you are probably going about this the wrong way,
your image is allocated and added in your bookmark changed, your notification does not trigger when there are no bookmarks initially. Hence you don't see the image. Call the bookmar changed when your table view inits or appears.
Probably the best way to achieve this is to perform a check in your numberOfRowsInSection method to return 1 if your data source is empty. Then in cellForRowAtIndexPath check if your data source is empty and if it is, create a custom cell that contains whatever you want. In heightForRowAtIndexPath you need to return your custom cell height if your datasource is empty, but only if you want the cell larger than the default. At least that is how I would approach it.
when bookmarks count is nil add one to your row method:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
int c;
c = bookmarks.count;
if(c == 0){
c = 1;
}
return c;
}
and then the same check again in your cellforrowatindexpath.
Another thing to be aware of in this situation is that if you're using core data and you're datasource is feeding off an entity, you will want to make sure your model matches. You can get some weird side-effect behavior in certain situations. This is especially true if you allow editing and core data has an empty model but you're tableview is still showing a cell.

Data not display UITableView?

In my application I parsed the data through NSXMLParser and made separate class to store that data from which i usually display the data. Everything works fine in simulator except the the title which is display in table cell with image. Images appears properly but the title not appear properly.
This is my code:-
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
[[NSBundle mainBundle] loadNibNamed:#"TableCell3" owner:self options:NULL];
cell = nibLoadedCell;
}
NewsInfo *aNewsInfo = [appDelegate.newsArray objectAtIndex:indexPath.row];
titleLabel.text = aNewsInfo.title;
imageLabel.image = aNewsInfo.smallImageData;
return cell;
}
and in this way i configured my TableCell3.xib
Now i want my title data in 2 rows in label of the TableCell3.
I already used both the way through xib attributes settings or through code.
Code which i used instead of this xib attributes settings are:-
titleLabel.lineBreakMode = UILineBreakModeWordWrap;
titleLabel.numberOfLines = 2;
titleLabel.text = aNewsInfo.title;
Now Can any one help me to figure out this prob i want to display my title in two rows of the table view cell.
Thanks in Advance.
Just increase the height of your label and give a try. If the height is too less to hold 2 lines, the label will truncate the contents to 1 line and end with the ellipsis.
Shouldn't you be accessing them by
cell.titleLabel.text = sometest;
cell.imageLabel.image = someImage;
and also ensure that the titleLabel and imageLabel are connected properly to the outlets. And pls check your naming for the variables. imageLabel is not a good choice if you want that to be an imageview.

iPhone: cornerRadius quality gets degraded

I have a UILabel that I create a radius on the layer, using cornerRadius. The ultimate goal is to make the label look like Apple does in the mail app.
It looks great at first, but once you drill down into that row and back a few times, the quality of the rounded edge starts to degrade. You can see in the screen shot, the left side is blocky.
Why would this be happening? It seems to happen after about 2 times of loading that view.
(source: puc.edu)
Here is my cell creation method:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier] autorelease];
}
Trip *trip = [fetchedResultsController objectAtIndexPath:indexPath];
cell.textLabel.text = trip.title;
cell.detailTextLabel.text = #"Date of trip";
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
// Create a nice number, like mail uses
UILabel *count = [[UILabel alloc] initWithFrame:CGRectMake(cell.contentView.frame.size.width - 50, 12, 34, 20)];
[count setText:[NSString stringWithFormat:#"%i",[[trip.rides allObjects] count]]];
[count setFont:[UIFont fontWithName:#"Helvetica-Bold" size:16]];
count.textAlignment = UITextAlignmentCenter;
count.backgroundColor = [UIColor grayColor];
count.textColor = [UIColor whiteColor];
count.layer.cornerRadius = 10;
[cell addSubview:count];
[count release];
return cell;
}
In every call to cellForRowAtIndexPath, you are creating a new count UILabel. Eventually there will be several overlapping views in the same place with the same antialiased curve, so it will look blocky.
Try creating the count UILabel only when a new cell is created, in the if (cell == nil) block. Otherwise, get the count label by tag.
if ( cell == nil ) {
cell = ...
count = ...
...
count.tag = 'coun';
[cell.contentView addSubview:count];
[count release];
} else {
count = (UILabel *)[cell viewWithTag:'coun'];
}
[count setText:[NSString stringWithFormat:#"%i",[[trip.rides allObjects] count]]];
Check to see if the tableview/cell is set to clear its context before drawing. I noticed I had similar issues with text on the cell.
I've seen some strange issues wherein it looks like Core Animation based properties are accumulative even though they shouldn't be. Your problem here might be caused by some kind of accumulative creep from changing the value of the corner radius repeatedly every time the cell is returned.
I would suggest testing if the corner radius already equals 10 before setting it again. (Although I would expect that to show up more with scrolling up and down than in reloading the view.)
Another possible problem would be that some subview is migrating causing a visual artifact.
Edit:
Instead of adding the label to the cell itself. Try adding it as a subview of the cell's content view.

iphone code - custom table instead of default one

i'm using a default style table (UITableViewCellStyleSubtitle)
i want to add more then one detailTextLabel in each row,
how can i customize it?
code:
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle
reuseIdentifier:CellIdentifier] autorelease];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
}
// Leave cells empty if there's no data yet
if (nodeCount > 0)
{
// Set up the cell...
ARecord *aRecord = [self.entries objectAtIndex:indexPath.row];
cell.textLabel.text = aRecord.lDate;
cell.detailTextLabel.text = aRecord.WNum;
// Only load cached images; defer new downloads until scrolling ends
//(!aRecord.appIcon) - use icon
if (!aRecord.appIcon)
{
if (self.tableView.dragging == NO && self.tableView.decelerating == NO)
{
[self startIconDownload:aRecord forIndexPath:indexPath];
}
// if a download is deferred or in progress, return a placeholder image
cell.imageView.image = [UIImage imageNamed:#"Placeholder.png"];
}
else
{
cell.imageView.image = aRecord.appIcon;
}
}
return cell;
}
The best way of doing this is to add a UILabel to the cell.contentView. You would do this when you initially create the cell. I've found two things to be especially helpful: to lay out the label on a table cell in a throwaway document in Interface Builder to determine the initial frame. It's also especially helpful to set the autoresizingMask so that the label will be resized appropriately when the cell is resized (due to autorotation, going into edit mode, etc.).
Finally, you'll need to set the table view's rowHeight to a higher value to accommodate the larger cells, otherwise you'll end up with overlapping cells.
Also, set a tag on your label to make it easy to retrieve with viewWithTag: when you go to update the text.
You could add the labels to cell.contentView.