I have a UITableView that displays content programmatically.
The cells load fine when first opened, but after scrolling they all show the same caption, which is, I assume, the last cells caption.
The underlying TableView that opens if a cell is selected still works fine.
I looked up the solutions on SO but they either didn't work for me or I'm too dumb to understand the Problem, which sees to be the reusing the cells for some kind of saving resources.
I will post the cellForRowAtIndexPath as I assume the Problem lies there, if any further code is needed please let me know.
- (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];
}
NSString *oneLine = [entrys objectAtIndex:position];
NSArray *lineComponents = [oneLine componentsSeparatedByString:#";"];
cell.textLabel.text = [lineComponents objectAtIndex:0];
cell.textLabel.textColor = [UIColor colorWithRed:0.0 green:0.8 blue:0.2 alpha:1.0];
if (position < [entrys count] -2 ) {
position++;
}
return cell;
}
Thanks in advance
You're not using the indexPath parameter at all. It should proably be:
NSString *oneLine = [entrys objectAtIndex:indexPath.row];
try this one instead of postion
NSString *oneLine = [entrys objectAtIndex:indexpath.row];
NSArray *lineComponents = [oneLine componentsSeparatedByString:#";"];
cell.textLabel.text = [lineComponents objectAtIndex:0];
cell.textLabel.textColor = [UIColor colorWithRed:0.0 green:0.8 blue:0.2 alpha:1.0];
or
if it still not work then your array is not initialized properly. initialize it
The problem is here
if (position < [entrys count] -2 ) {
position++;
}
your rows in table are larger than the array count entrys and due to this condition your position is incremented to last object and after that this condition never gets called thus your position points to last object.
Could you tell what you have returned from your tableView:numberOfRowsInSection: method ?
Related
I am using UITableView. When a book is downloaded i am adding a checkmark image to my table. And i have done this. But when am scrolling my table am getting the image even for non-downloaded books (i.e) my table cell are reused. For this i googled and checked my code with that. Everything seems to be the same. Here is my code,
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UIImage *cellImage= [cacheImage getCachedImage:[listOfThumImages objectAtIndex:indexPath.row]];
if(cellImage == nil)
{
DeviantDownload *download;
download = [DownloadsArray objectAtIndex:indexPath.row];
cellImage = download.image;
if (cellImage == nil)
{
download.delegate = self;
}
NSLog(#"cellImage%#",cellImage);
UIImageView *imgView;
static NSString *CellIdentifier = #"";
cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
imgView1 = [[UIImageView alloc] initWithFrame:CGRectMake(680, 60, 40, 40)];//self.view.bounds.size.width-
[imgView1 setImage:[UIImage imageNamed:#"Downloaded.png"]];
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
if([defaults objectForKey:#"firstRun"])
{
if([[[appDelegate selectDB] valueForKey:#"bookname"] containsObject:[listOfBooks objectAtIndex:indexPath.row]] )
{
NSString *cellValue = [listOfBooks objectAtIndex:indexPath.row];
cell.contentView addSubview:imgView1];
}
return cell;
}
}
}
What's wrong with my code? Kindly help me out. Thanking You.
If you want that a cell does not display the image then simply remove the imageview, for that cell. set a view.tag for the image view, and retrieve it, then remove it.
What you are doing now, is to add a image sub view as soon as you need it for a cell, and later reuse that cell for all other rows. But you never removed the imageview for cells that dont need it.
CheckMarks with UITableView is little complicated then what it seems. First of all you'll have to save the status of your row which already has the bookmark. And, compare it in your cellForRowAtIndexPath method. What you can do is create on NSMutableArray. Save 1 for downloaded book and 0 for non-downloaded book. In your cellForRowAtIndexPath method compare [array objectAtIndex:indexpath.row] and set the image accordingly.
Also, change :
static NSString *CellIdentifier = #"";
To :
static NSString *CellIdentifier = #"MyCell";
I have an app consisting of a TabBar with a few TabBarControllers. One Controller contains a very simple table, which is supposed to display the contents of a NSMutableDictionary. When you hit the appropriate button, the Dictionary is updated in a separate Controller and the view switches to the UITableViewController, displaying the newly updated table.
I can see the Dictionary being updated. But the TableView never reflects the changes. In fact, it seems to display the changes only the 1st time I enter that screen.
I have tried [self table.reloadData] and while it gets called, the changes aren't reflected to the UITableView.
Does anyone have any suggestions? I am happy to post code, but am unsure what to post.
Update: the table is updated and refreshed properly only the 1st time it is displayed. Subsequent displays simply show the original contents.
Background:
The tableview gets filled from a dictionary: appDelegate.currentFave. The tableview should get refreshed each time the ViewController is invoked by the TabBarController.
- (void)viewWillAppear:(BOOL)animated
{
NSLog(#"in viewWillAppear");
[super viewWillAppear:animated];
[self loadFavesFile];
[self.tableView reloadData];
}
// load the Favorites file from disk
- (void) loadFavesFile
{
// get location of file
NSString *path = [self getFavesFilePath];
// The Favorites .plist data is different from the Affirmations in that it will never be stored in the bundle. Instead,
// if it exists, then use it. If not, no problem.
if ([[NSFileManager defaultManager] fileExistsAtPath:path]) {
// read Faves file and store it for later use...
NSMutableDictionary *tempDict = [NSMutableDictionary dictionaryWithContentsOfFile:path];
appDelegate.sharedData.dictFaves = tempDict;
// grab the latest quote. Append it to the list of existing favorites
NSString *key = [NSString stringWithFormat:#"%d", appDelegate.sharedData.dictFaves.count + 1];
NSString *newFave = [NSString stringWithFormat:#"%#", appDelegate.currentFave];
[appDelegate.sharedData.dictFaves setObject:newFave forKey:key];
} else {
NSLog(#"Favorites file doesn't exist");
appDelegate.sharedData.dictFaves = nil;
}
}
// this gets invoked the very first call. Only once per running of the App.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
// reuse or create the cell
static NSString *cellID = #"cellId";
UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:cellID];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellID];
}
// allow longer lines to wrap
cell.textLabel.numberOfLines = 0; // Multiline
cell.textLabel.lineBreakMode = UILineBreakModeWordWrap;
cell.textLabel.font = [UIFont fontWithName:#"Chalkduster" size:(16)];
cell.textLabel.textColor = [UIColor yellowColor];
// NOTE: for reasons unknown, I cannot set either the cell- or table- background color. So it must be done using the Label.
// set the text for the cell
NSString *row = [NSString stringWithFormat:#"%d", indexPath.row + 1];
cell.textLabel.text = [appDelegate.sharedData.dictFaves objectForKey:row];
return cell;
}
I found the problem. I was not properly initializing and assignng the TableView in my view controller. See below
- (void)viewDidLoad
{
[super viewDidLoad];
tableView = [[UITableView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame] style:UITableViewStylePlain];
tableView.dataSource = self;
tableView.delegate = self;
tableView.backgroundColor=[UIColor blackColor];
self.view = tableView;
}
Assuming the code you have put up is correct, you want to use [self.table reloadData]. You have the . in the wrong place.
I had this same problem yesterday, for me it turned out I had set the wrong file owner in interface builder and hadn't set up the data source and delegates for the table view properly.
Try going into interface builder and right-clicking on the file owner, this should show you if anything isn't connected up properly.
You should make sure that your Interface Builder connections are set up properly, but what this problem really sounds like is that you have your UITableViewCell setup code in cellForRowAtIndexPath: inside your if(cell == nil) statement. Which it shouldn't be. Let me explain. If you have a list of cells, and you want to set the titles to each cell to a string in an array called myArray, right now your (incorrect) code looks like this:
- (UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"cellIdentifier"];
if (cell == nil) {
// No cell to reuse => create a new one
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:#"cellIdentifier"] autorelease];
[[cell textLabel] setText:[myArray objectAtIndex:[indexPath row]]];
}
return cell;
}
Can you see the problem with that logic? The cell will only get an updated title if no reusable cell can be found, which, in your case, sounds like the situation. Apple says that you should create a 'new' cell each time cellForRowAtIndexPath: is called, which means that you put all of your setup code outside of the if(cell == nil) check.
Continuing with this example, the proper code would look like this:
- (UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"cellIdentifier"];
if (cell == nil) {
// No cell to reuse => create a new one
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:#"cellIdentifier"] autorelease];
}
[[cell textLabel] setText:[myArray objectAtIndex:[indexPath row]]];
return cell;
}
This way, the cell gets assigned the proper string whether or not a reusable cell is found and so calling reloadData will have the desired effect.
I have UITableViewController which contains a list of items. Now, I want the list to be automatically scrolled to a item (index = bestOne ) once the view appears. Meanwhile I want the item to be colored into red and be labeled as Marked.
My code roughly achieves what I want. But, I actually see more than one red items iterating: every 10 items, there is a red item.
I am quite new to iphone development, I figure it might have something to do with reusable cells. But I am not exactly sure why. Can anybody suggest one way to solve this issue? Thanks in advance.
(void)viewDidAppear:(BOOL)animated
{
if (self.bestOne != -1)
{
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:self.bestOne inSection:0];
[self.tableView scrollToRowAtIndexPath: atScrollPosition: animated:YES];
}
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:reuseIdentifier:CellIdentifier] autorelease];
}
cell.textLabel.text = [self.array objectAtIndex:indexPath.row];
if (indexPath.row == self.bestOne)
{
cell.detailTextLabel.text = #"Marked";
cell.textLabel.textColor = [UIColor redColor];
}
return cell;
}
You are right about the reusable cells part.
Your code should be something like –
cell.textLabel.text = [self.array objectAtIndex:indexPath.row];
if (indexPath.row == self.bestOne)
{
cell.detailTextLabel.text = #"Marked";
cell.textLabel.textColor = [UIColor redColor];
}
else
{
cell.detailTextLabel.text = #"";
}
On reuse, you get the exact cell that you had set before. While other cells are undistinguishable, the marked cell stands out with its specifically set detailTextLabel. You need to reset it before you can use it as an unmarked cell.
you look like you are on the right track with the color issue, you may accumulate red colored text cells, if you aren't calling [tableView reloadData] or reloading the old red cells specifically, which you would want to do if you have a large table. your scrolling looks good, don't know why that wouldn't work.
I have created a TableView in my application with 5 sections in it.
Sections 1 - 4 only contain one row each for the minute and section 5 contains 5 rows.
Everything works fine until I scroll the TableView off the screen. In my first section and row (cell) I have the accessoryView set to a UILabel with some text in it.
Every other cell has the disclosure button as the accessoryType.
When I scroll the tableView the text I have in the first cell somehow appears in the the last cell!?
I have set up my data by adding NSStrings to array's and then adding them as dictionaries to an NSMutableArray.
And here is my cell set up:
- (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] autorelease];
}
// UISwitch *aUISwitch = [[[UISwitch alloc]initWithFrame:CGRectZero]autorelease];
// Configure the cell.
NSDictionary *dictionary = [listOfSettings objectAtIndex:indexPath.section];
NSArray *array = [dictionary objectForKey:#"Settings"];
NSString *cellValue = [array objectAtIndex:indexPath.row];
cell.textLabel.text = cellValue;
if([cellValue isEqualToString:#"Status"]){
UILabel *viewLabel = [[UILabel alloc]initWithFrame:CGRectMake(0, 0, 100, 20)];
[viewLabel setText:#"Connected"];
cell.accessoryView = viewLabel;
[viewLabel release];
}
else{
cell.accessoryType = UITableViewCellAccessoryDetailDisclosureButton;
}
return cell;
}
I know cells get deleted/removed when they go off screen so I presume this has something to do with it? What is the recommended practice for dealing with cells that go off screen and reappear?
just at quick glance... in the else statement, not only do you need to set the cell.accessoryType, but also set the cell.accessoryView=nil;
the accesoryView is still there as the cell was recycled.
I have the following code which is trivial at first sight. I simply set want to set the font type to Georgia with a size of 14 if the cell is from the result of a search or if there is a count of zero in my students array.
However, with this particular code cell that's last in my tableView is taking on the font of Georgia with size 14. All other cells are working proper. Where in my code is the logic wrong?
- (UITableViewCell *)tableView:(UITableView *)tv cellForRowAtIndexPath:(NSIndexPath *)indexPath {
NSInteger row = [indexPath row];
NSInteger section = [indexPath section];
static NSString *CellIdentifier = #"Student";
cell = [tv dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:CellIdentifier] autorelease];
}
// Configure the cell
if([studentsSearch count] > 0) {
cell.text = (NSString *)[[[studentsSearch objectAtIndex:section] objectAtIndex:row] valueForKey:#"name"];
cell.accessoryType = UITableViewCellAccessoryDetailDisclosureButton;
} else {
if(isSearching == YES)
cell.text = #"No students available.";
else
cell.text = #"No students have been added for this school.";
cell.font = [UIFont fontWithName:#"Georgia" size:14];
cell.accessoryType = UITableViewCellAccessoryNone;
}
return cell;
}
EDIT
What appears to be happening is when the view controller gets instantiated and pushed on top of the navigation controller's stack, my studentsSearch array is nil. I populate it within that controller.
So upon initialization, the cell has its font set to Georgia with a size of 14 because the count is < 0. However, once I populate the studentsSearch array and reload the tableView's data, the font seems to be sticking from when the view first got initialized.
I suppose now I need to find how to set the font back to that cell to what the default is.
I'm not quite sure what you're asking, but I do note that you're only setting the font to Georgia 14 when you have a search result; otherwise, you're ignoring it. If you have a cell with it's font set in the second if/then branch, and then retrieve that cell (using dequeueReusableCellWithIdentifier:), it will already have it's font set.
The simplest solution is to add
cell.font = [UIFont systemFontOfSize: 14];
after
cell.text = (NSString *)[[[...
cell.accessoryType = ...
in the first branch.
Keep in mind that table cells are recycled. Let's say your table has 15 visible rows. That means you have approximately 15 cells (or a few more) that get created and, as I said, recyled. Even if your table has hundreds of rows, it will still use the same 15 cells.
In this case, you're never resetting the font size, so once you set that font size on a cell, it will be used on any row after it that re-uses the cell.
So, if your studentsSearch count > 0, you need to make sure to set the font size to whatever your baseline is (17?).
I'd suggest that you identify the 'special' cell by giving it a different cell identifier.
In this case, you'd request the special cell with cell reuse identifier, e.g. #"None", and if cell has not yet been created, then create one and set its font.
This way, you create an extra cell with a special identifier, and it is kept separate from the other regular cells in your table.
- (UITableViewCell *)tableView:(UITableView *)tv cellForRowAtIndexPath:(NSIndexPath *)indexPath {
NSInteger row = [indexPath row];
NSInteger section = [indexPath section];
static NSString *StudentCellIdentifier = #"Student";
static NSString *NoneCellIdentifier = #"None";
// did we find students?
BOOL found = [studentsSearch count] > 0;
// get/create correct cell type
cell = [tv dequeueReusableCellWithIdentifier:(found ? StudentCellIdentifier : NoneCellIdentifier)];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithFrame:CGRectZero
reuseIdentifier:(found ? StudentCellIdentifier : NoneCellIdentifier)];
}
// return a student, or None cell if no studnts found
if( found )
{
cell.text = (NSString *)[[[studentsSearch objectAtIndex:section] objectAtIndex:row] valueForKey:#"name"];
cell.accessoryType = UITableViewCellAccessoryDetailDisclosureButton;
}
else
{
if(isSearching == YES)
cell.text = #"No students available.";
else
cell.text = #"No students have been added for this school.";
cell.font = [UIFont fontWithName:#"Georgia" size:14];
cell.accessoryType = UITableViewCellAccessoryNone;
}
return [cell autorelease];
}