Problem with text in detailTextLabel of UITableViewCell

I have an odd problem when changing the detailTextLabel property of a UITextViewCell. If I change the label to an empty string, using something like:

cell.detailTextLabel.text = @"";

Then at a later point change the text to a different non-empty string, the string does not appear. I know that correct detail text label is being set to the non-empty string (I've compared memory addresses, and also, if I don't change the string to the empty string, the string changes and displays correctly).

I've tried things like making sure that the text is black, etc, and have compared the size of the label when it works and when it doesn't (in both cases, it is zero). As far as I can tell, the text is actually set
correctly, it seems to be a drawing issue. I'm not sure if this is a fairly common problem, but if anybody know how to fix it, or further things I could check, I'd be very grateful.

MacBook Pro, iOS 4

Posted on Oct 27, 2010 1:20 AM

Reply
7 replies

Oct 27, 2010 3:57 AM in response to m_userName

When you change the text in a cell, you need to also change the corresponding text in the data source. Are you doing that? You might also consider using [reloadRowsAtIndexPaths:withRowAnimation:|http://developer.apple.com/library/io s/documentation/UIKit/Reference/UITableView Class/Reference/Reference.html#//appleref/doc/uid/TP40006943-CH3-SW40]. In that case, just update the data source and reload. You won't need to find the cell yourself.

\- Ray

Oct 27, 2010 5:49 AM in response to RayNewbie

I'm not sure what you mean by changing the corresponding text in the data source. The cell in question belongs to a table view owned by the parent view controller, which is the data source. The child view keeps a pointer to its parent view, and I'm actually changing the detail view directly through the parents table view property. Is this what you meant?

Oct 28, 2010 4:22 AM in response to m_userName

m_userName wrote:
I'm not sure what you mean by changing the corresponding text in the data source.

I should have explained that better, since you might have assumed I meant the data source object. I was referring to the data structure used by tableView:cellForRowAtIndexPath: to load each cell. For instance, take a look at tableView:cellForRowAtIndexPath: in this example code I posted in one of your recent threads: [Re: Trouble tracking down EXC BADACCESS error|http://discussions.apple.com/thread.jspa?messageID=12436920&#12436920]. In that case the data for each cell is obtained from the tableDataSource array:

// Set up the cell...
NSDictionary *dictionary = [self.tableDataSource objectAtIndex:indexPath.row];
cell.textLabel.text = [dictionary objectForKey:@"Title"];
return cell;

So what I meant in my last post is that whenever you change the data in a cell (the detailTextLabel in this case), you must also change the data which tableView:cellForRowAtIndexPath: will use when replacing that cell. Otherwise whatever change you made will be reversed as soon as that cell is replaced (which usually happens when the cell is scrolled out of view, then scrolled back into view, but can happen at other times as well).

Here's an example of how to use [reloadRowsAtIndexPaths:withRowAnimation:|http://developer.apple.com/library/io s/documentation/UIKit/Reference/UITableView Class/Reference/Reference.html#//appleref/doc/uid/TP40006943-CH3-SW40] to change the detail text label of one of the cells. Note that we don't need to find the cell and modify the label directly. We just change the data source for the target row then reload the cell for that row:

// RootViewController.m
#import "RootViewController.h"
#define kDetailText @"Detail Text"
@implementation RootViewController
@synthesize data, tableDataSource;
- (void)viewDidLoad
{
[super viewDidLoad];
level = [self.navigationController.viewControllers count];
NSLog(@"%s: level=%d", _func_, level);
if (level <= 1) {
NSString *Path = [[NSBundle mainBundle] bundlePath];
NSString *DataPath = [Path stringByAppendingPathComponent:@"data.plist"];
NSDictionary *tempDict = [[NSDictionary alloc] initWithContentsOfFile:DataPath];
self.data = tempDict;
[tempDict release];
self.tableDataSource = [data objectForKey:@"Children"];
self.navigationItem.title = [data objectForKey:@"Title"];
}
else
; // tableDataSource and navigationItem.title were set by previous controller

// NSLog(@"%s: self.tableView=%@", _func_, self.tableView);
// make a nav bar button to toggle the detail text for row 0
UIBarButtonItem *detailBBI = [[UIBarButtonItem alloc]
initWithTitle:@"Detail" style:UIBarButtonItemStylePlain
target:self action:@selector(toggleDetailTextForRow0)];
self.navigationItem.rightBarButtonItem = detailBBI;
[detailBBI release];
// initialize the detail text
detailText = kDetailText;
}
- (void)toggleDetailTextForRow0 {
if ([tableDataSource count]) {
detailText = [detailText isEqualToString:@""] ? kDetailText : @"";
// get index path for row 0 and reload that row
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:0 inSection:0];
NSArray *indexPathArray = [NSArray arrayWithObject:indexPath];
[self.tableView reloadRowsAtIndexPaths:indexPathArray
withRowAnimation:UITableViewRowAnimationNone];
}
}
- (void)viewDidDisappear:(BOOL)animated {
[super viewDidDisappear:animated];
if (self.navigationController == nil) {
NSLog(@"%s: *POPPED* level=%d", _func_, level);
}
}
#pragma mark Table view methods
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
// Customize the number of rows in the table view.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [tableDataSource count];
}
// Customize the appearance of table view cells.
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = @"TableViewCell";

UITableViewCell *cell = (UITableViewCell*)
[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
// NSLog(@"%s: level=%d row=%d", _func_, level, indexPath.row);
cell = [[UITableViewCell alloc]
initWithStyle:UITableViewCellStyleValue1
reuseIdentifier:CellIdentifier];
}
// set the text label
NSDictionary *dictionary = [self.tableDataSource objectAtIndex:indexPath.row];
cell.textLabel.text = [dictionary objectForKey:@"Title"];
// set the detail text label
if (indexPath.row == 0)
cell.detailTextLabel.text = detailText;
else
cell.detailTextLabel.text = kDetailText;
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
// NSLog(@"%s: tableDataSource=%@", _func_, self.tableDataSource);
NSDictionary* dictionary = [self.tableDataSource objectAtIndex:indexPath.row];
// NSLog(@"%s: dictionary=%@", _func_, dictionary);
NSArray* children = [dictionary objectForKey:@"Children"];
// NSLog(@"%s: children=%@", _func_, children);
if(children)
{
// set up the next controller
RootViewController* rootViewController = [[RootViewController alloc]
initWithNibName:@"RootViewController" bundle:[NSBundle mainBundle]];
rootViewController.navigationItem.title = [dictionary objectForKey:@"Title"];
rootViewController.tableDataSource = children;
// push the next controller onto the stack
[self.navigationController pushViewController:rootViewController animated:YES];
// NSLog(@"%s: stack=%@", _func_, self.navigationController.viewControllers);
[rootViewController release];
}
}
- (void)dealloc {
NSLog(@"%s: level=%d", _func_, level);
[tableDataSource release];
[data release];
[super dealloc];
}
@end

In the above, the data source for the text label is the tableDataSource array while the data source for the detail label text is just two hard-coded strings for the purpose of demonstration. The detailText ivar is the data source for the detail label in row 0, and the string at that ivar is changed in toggleDetailTextForRow0 whenever the Detail button in the nav bar is tapped. Also note that you can add animation to the label change by resetting the second arg of reloadRowsAtIndexPaths::

- Ray

Oct 28, 2010 8:10 AM in response to RayNewbie

Thanks for the feedback 🙂

I think I understand what you're saying: if the parent controller is the datasource of a tableview and you change the detail text in the child view controller, then next time the cell is obtained from the parent controller (by calling cellForRowAtIndexPath or otherwise), it will overwrite the values that you have set.

In my case, the parent controller is the datasource, but the detailTextView text is not set by the parent view controller, it is only set by the child view controller, so it shouldn't be overwritten in cellForRowAtIndexPath (unless a completely new cell is returned, in which case it should revert to the empty string).

I've checked and it cellForAtIndexPath in the parent controller, and it is never called after the detailTextView has been set by the child controller. I've checked the detail label of the text and it is correct. This seems to be the cell that is being displayed, since the text label is correct (and it isn't creating a new cell in cellForIndexPath).

The odd thing about it is, if I set the detail text label to a non-empty string, such as @"x", and then set it to something else at a later point, it works fine -the detail label text is the second thing I set it to, as expected.

Oct 29, 2010 3:12 AM in response to m_userName

As further testing, I have now changed the text so that it is also changed in the parent controller (which is the table view's data source). I have exactly the same problem: if I set the detail label text to the empty string, and then set it to another string, it still does not display any text; if I set it to a non-empty string, and then set it to something different, it displays the new text that I have set it to.

Are there any known things to look out for if you are setting a text label to an empty string?

This thread has been closed by the system or the community team. You may vote for any posts you find helpful, or search the Community for additional answers.

Problem with text in detailTextLabel of UITableViewCell

Welcome to Apple Support Community
A forum where Apple customers help each other with their products. Get started with your Apple Account.