Double selection of a uitableviewcell in Custom Cell - objective-c

i have an issue regarding UitableViewCell. the issue is that i have made a custom cell and i have a check box image button in that cell. i check and uncheck it. it works fine but the issue is that when i select Row # 1. it also selects row # 10 same goes with other rows like for 2 it will auto select row # 11. i am showing 10 rows at a time.
here is my code for CellForIndexPath
static NSString *cellIdentifier = #"Cell";
InterestsTableViewCell *cell = (InterestsTableViewCell *) [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (cell==nil) {
NSArray *arrayNibs = [[NSBundle mainBundle] loadNibNamed:#"InterestsTableViewCell" owner:self options:nil];
cell = [arrayNibs objectAtIndex:0];
cell.delegate = self;
cell.total = [dataArray count];
}
cell.tag = indexPath.row;
cell.lblTitle.text = [dataArray objectAtIndex:indexPath.row];
if (indexPath.row==0) {
cell.imgBg.image = [UIImage imageNamed:#"tableCell_top_default.png"];
}else if(indexPath.row == [dataArray count]-1){
cell.imgBg.image = [UIImage imageNamed:#"tableCell_bottom_default.png"];
}else{
cell.imgBg.image = [UIImage imageNamed:#"tableCell_middle_default.png"];
}
return cell;
Plus i am detecting touch so that i can change the background image (i have an other image as background). Code for Touch Began (in custom cell is below)
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
//NSLog(#"%i",tag);
isSelected = !isSelected;
btnTickMark.selected = !btnTickMark.selected;
(isSelected ? (onImage = YES) : (onImage = NO));
Can somebody help me in this issue that why 2 rows are selected when i click a row.
Thanks in advance

This is because UITableView dequeues the cell. As you are showing 10 rows per screen it totally fits, that row 11 appears checked as it is dequeued from row 1.
To avoid that behavior you have to add a check to tableView:cellForRowAtIndexPath: to set your checked parameter for each cell – like the text you set for every cell.

Try this:
NSArray *arrayNibs = [[NSBundle mainBundle] loadNibNamed:#"InterestsTableViewCell" owner:self options:nil];
for (id currentObject in arrayNibs){
if ([currentObject isKindOfClass:[UITableViewCell class]]){
cell = (InterestsTableViewCell *) currentObject;
cell.Delegate = self;
cell.total = [dataArray count];
break;
}
}
and let me know if this works for you.

Quick Fix - change this line from
InterestsTableViewCell *cell = (InterestsTableViewCell *) [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
to
InterestsTableViewCell *cell = nil;
Its not good from a memory/efficiency perspective because you won't be reusing the cells, instead will be reloading one from nib each time - but it will demonstrate whether what Florian Mielke is saying is correct (and his recommended approach will provide a better solution long term).

Related

TableView with little less performance

I'll try to implement a TableView with 2 different kinds of cells, the first one is a higher Cell with a fullwidth image inside, all other cells got a little thumb image on the left side.
My problem it the performance of the TableView. If I scroll a list of maybe 20 items it jerks a bit. I've red something the performance and I'll hope the code is not so bad:
"Caching of images is not necessary to raise the performance" Is this right?
Does I reuse the cells in the right way.
Is that the normal way to use 2 different kinds of Cells?
Here is the important Part:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
if (indexPath.section == 0 && indexPath.row == 0) {
return 160;
}
return 60;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *cellName = [[NSString alloc] init];
// [...]
if(indexPath.section == 0 && indexPath.row == 0){
cellName = #"FirstMainCell";
CellTemplateFirstNews *cell = [tableView dequeueReusableCellWithIdentifier:cellName];
if(cell == nil){
cell = [[[NSBundle mainBundle] loadNibNamed:#"CellTemplateFirstNewsView" owner:nil options:nil] objectAtIndex:0];
}
NSURL *urlRowImage = [NSURL URLWithString:[[NSString alloc]initWithFormat:#"http://webserver.de/inhalte/news/title/%#", detailDataNews.title_picture]];
NSData *dataRowImage = [NSData dataWithContentsOfURL:urlRowImage];
UIImageView *firstNewsImageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 320, 160)];
firstNewsImageView.backgroundColor = [UIColor clearColor];
firstNewsImageView.opaque = NO;
firstNewsImageView.image = [UIImage imageWithData:dataRowImage];
cell.backgroundView = firstNewsImageView;
// [...]
return cell;
}else{
cellName = #"MainCell";
CellTemplateNews *cell = [tableView dequeueReusableCellWithIdentifier:cellName];
if(cell == nil){
cell = [[[NSBundle mainBundle] loadNibNamed:#"CellTemplateNewsView" owner:nil options:nil] objectAtIndex:0];
}
NSURL *urlRowImage = [NSURL URLWithString:[[NSString alloc]initWithFormat:#"http://webserver.de/inhalte/news/cover/%#", detailDataNews.cover_picture]];
NSData *dataRowImage = [NSData dataWithContentsOfURL:urlRowImage];
UIImage *rowImage = [UIImage imageWithData:dataRowImage];
cell.thumbImage.image = rowImage;
// [...]
return cell;
}
}r
I think the main problem is the synchronous network request that's happening for every cell, whether it's reused or not. The culprit is dataWithContentsOfURL:.
Check out this apple sample code, or google the phrase "ios lazy table images". In this SO answer, I provide a fairly simple to implement method that takes care of the loading an image asynch, then finding and updating the correct table view row upon completion.
One posibility is that you've forgotten to enter the CellIdentifier in your Xib. In fact the reuseIdentifier method needs your cell to have the same identifier, but you never set it when you create your cell. Those cells in your Xib have to have their identifier entered.
Do not alloc-init any object in cellForRowAtIndexPath You are probably leaking massive memory. Remember, this method called every time a cell comes into view, even cells that have been previously shown.
Also, your assignments to string variables are redundant. It is sufficient to do it like this.
BOOL firstCell = (indexPath.row==0 && indexPath.section==0);
NSString *cellIdentifier = firstCell ? #"FirstMainCell" : #"MainCell";
UITableViewCell *genericCell = [tableView
dequeueReusableCellWithIdentifier:cellIdentifier];
if (firstCell) {
cell = (CellTemplateFirstNews*) genericCell;
// configure...
}
else {
cell = (CellTemplateNews*) genericCell;
// configure...
}
return cell;
The other possible reason for your lag is the synchronous call to the web service. You are doing this each time the cell becomes visible. You need to load the images lazily and update the UI when necessary.

Font size in UITextView change unexpectedly

I have a table view with several table view cell. The table view cell consists of title (using UILabel), picture (using UIWebView) and summary (using UITextView).
When I use UIImage for the picture, everything runs well. But then, I decided to display the pic by using resized UIWebView instead of UIImage. Some of the summary in the UITextView change unexpectedly.
When I scrolled the table, the problem will sometimes disappear. But it can randomly appear again on different table view cell.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
TableViewCell *cell = (TableViewCell *) [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
[[NSBundle mainBundle] loadNibNamed:#"TableViewCell" owner:self options:nil];
cell = table;
self.table = nil;
}
//Configure the cell...
Article *article = [_articleRepository fetchArticleById:[articleIds objectAtIndex:indexPath.row]];
cell.headline.text = article.articleTitle;
// Remove html tag
NSString *substringContent = [self stringByStrippingHTML:article.articleContent];
cell.content.text = substringContent;
cell.selectionStyle = UITableViewCellSelectionStyleGray;
ImageRepository *imageRepository = [[ImageRepository alloc]init];
Image *image = [imageRepository fetchImageById:article.articleImage];
NSMutableString *mutUrl = [[NSMutableString alloc]initWithString:image.imageUrl];
[mutUrl insertString:#"_thumb" atIndex:[mutUrl length]-4];
NSString *stringUrl = [[NSString alloc]initWithString:mutUrl];
NSString *htmlImage = [NSString stringWithFormat:#"<html><head><style type=\"text/css\">body{margin: 0; padding: 0;}</style></head><body><img src=\"%#\"></body></html>", stringUrl];
[cell.image loadHTMLString:htmlImage baseURL:nil];
return cell;
}
It could be due to reuse of cells in the tableview that make ur problem appear randomly across cells. Would help if you posted code of what you've done.
EDIT: Try changing ur portion of the code to the one given below.
if (cell == nil) {
NSArray *topLevelObjects = [[NSBundle mainBundle] loadNibNamed:#"TableViewCell" owner:self options:nil];
cell = [topLevelObjects objectAtIndex:0];
}
Some questions:
1. Why are you doing cell = table & self.table = nil ?

Reloading searchResultsTableView

I have, in my main tableView, some custom cells (cells with an imageView, basically).
The imageView is set only if a value on my plist is false. Then, when it's true, the imageView is nil.
Basically when the user enters the detailView, the value is set to YES and the cell.imageView is nil.
And it's okay, it works
I'm using a searchDisplayController, when i search for something that has a cell.imageView, going into the detailView and then coming back to the searchResultsTable, the cell has still the image, while it shouldn't, but the main tableView has the correct cell (so, with no image).
I thought that it could depend on searchResultsTableView, but i'm not sure.
I tried with
[self.searchDisplayController.searchResultsTableView reloadData];
with no effect.
How could i reload the searchResultsTableView so that it shows the right cells, those with the image and those that don't have the image anymore?
Any help appreciated!
EDIT
This is my cellForRowAtIndexPath method:
- (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];
}
NSArray *rows;
if (tableView == self.searchDisplayController.searchResultsTableView) {
rows = filteredList; //for search
} else {
NSDictionary *section = [localSortedTips objectAtIndex:indexPath.section];
rows = [section objectForKey:#"Rows"];
}
NSDictionary *item = [rows objectAtIndex:indexPath.row];
cell.textLabel.text = [item objectForKey:#"name"];
if ([[item valueForKey:#"isRead"] boolValue] == NO) {
cell.imageView.image = [UIImage imageNamed:#"unread.png"];
} else {
cell.imageView.image = nil;
}
cell.textLabel.font = [UIFont boldSystemFontOfSize:15.0];
cell.textLabel.adjustsFontSizeToFitWidth = YES;
return cell;
}
If I understood you right, then you can have a workaround but searching again with the same search string:
if (self.searchDisplayController.active) {
self.searchDisplayController.searchBar.text = self.searchDisplayController.searchBar.text;
}
put it in viewWillAppear: or viewDidAppear: which will be called each time the view is shown up (eg. you go back from the detail view to your search view). And reloading the data in this place would be nice too, to get the right data (for example if you marked the cell as read like in your sample code)
Just [self.tableView reloadData]; and not the searchResultsTableView (it will be automatically use the updated data after the new search)
It sounds as if perhaps your cells are being recycled and not reset properly. UITableView uses view recycling, so it's important that if you do something such as set an image you make sure it is explicitly set even when their isn't an image to display.
If you share your cellsForRowAtIndexPath code you might be able to get some more help.

Is there a way to customize UISearchDisplayController cell

I am using UISearchDisplayController to search and would like to add so more elements to each cell if that is possible. Did some searching but couldn't find any information. The only way is to reproduce it with tableview. Is there any other properties i can set other then textlabel.text
Thanks in advance!
You can change the cell completely.
The following snippet relies on two subclasses of UITableCell, ANormalCell & ASearchCell.
Caveat: This code has not been compiled but you get the gist?
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *normalCellReuseIdentifier = #"ANormalCell";
static NSString *searchCellReuseIdentifier = #"ASearchCell";
UITableViewCell* cell = nil;
if (tableView != self.searchDisplayController.searchResultsTableView) {
cell = (ANormalCell*)[self.tableView dequeueReusableCellWithIdentifier:normalCellReuseIdentifier];
if (cell == nil) {
NSArray* topLevelObjects = [[NSBundle mainBundle] loadNibNamed:#"ANormalCell" owner:nil options:nil];
cell = (ANormalCell*)[topLevelObjects objectAtIndex:0];
}
} else {
cell = (ASearchCell*)[self.tableView dequeueReusableCellWithIdentifier:searchCellReuseIdentifier];
if (cell == nil) {
NSArray* topLevelObjects = [[NSBundle mainBundle] loadNibNamed:#"ASearchCell" owner:nil options:nil];
cell = (ASearchCell*)[topLevelObjects objectAtIndex:0];
}
}
return cell;
}
Very possible. All of the tableView datasource methods are called with a tableView parameter. If
if (tableView == searchController.searchResultsTableView)
then alter the cell by adding subviews, or customizing properties. Same approaches apply for custom cells in this case as in any other.
Yes you can set cell.imageView , cell.accessoryView , cell.BackGroundView .. etc.
read this UITableViewCell documentation for further information

How to get index of every item in an array Objective-C

For an iPhone app I am developing I need to assign custom uitableviewcell images based on the integers of arbitrary items in an array. I noticed while doing some testing that indexPath of row only returns indices for the view shown, so basically I need to know how to take an array, of arbitrary size, let's say right now it has 10 items, and those 10 items are in a table, each item a cell, I need each item to have an index like item 1 is index 0, item 2 is index 1 and so on. So my code would read, if the index == 0, then display this image in the cell, if the index != 0 then display another. I tried that but like I said if I scrolled to the bottom of my tableview it would reassign whichever table item is at the top of the view to 0, so as I scrolled the images kept changing. So basically i need help assigning the images based on an index in my array rather than on the index of the table.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *MyIdentifier = #"MyIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:MyIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:MyIdentifier] autorelease];
}
cell.detailTextLabel.lineBreakMode = UILineBreakModeWordWrap;
cell.detailTextLabel.numberOfLines = 1;
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
NSString *title =[[stories objectAtIndex: indexPath.row] objectForKey: #"summary"];
NSString *title2 =[[stories objectAtIndex: indexPath.row] objectForKey: #"title"];
NSString *dayOfMonthString = [title substringWithRange: NSMakeRange(2, 2)];
int dateChooser = [dayOfMonthString intValue];
NSString *monthString = [title substringWithRange: NSMakeRange(0, 2)];
int monthChooser = [monthString intValue];
cell.textLabel.text =title2;
cell.imageView.image =
[UIImage imageNamed: [NSString stringWithFormat: #"cal%d.png", dateChooser]];
if (monthChooser == 1 && (INDEX COMPARISON CODE???){
UIImageView *myImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"Jan1.png"]];
[cell setBackgroundView:myImageView];
}
Your problem is not getting the right index for the right cell. The row property of the indexPath do correspond to the index of the cell in the whole list of cells, not the index of the visible cells only, so exactly as you expected initially.
I bet your problem is that you don't use the reuse mechanism of UITableViewCells correctly
.
When you scroll in your TableView, UITableViewCells that are not on screen anymore are "recycled" and reused to display new cells onscreen, in order to avoid too much allocations and useless initializations that would else slow down the scrolling of your tableView.
The correct code pattern for returning a cell is the following:
-(UITableViewCell*)tableView:(UITableView*)tableView cellForRowAtIndexPath:(NSIndexPath*)indexPath
{
// Try to retrieve a previously created cell that is not used anymore
// That's the "recycling" part, we try to reuse a cell instead of creating a new one if possible
UITableViewCell* cell = [tableView dequeueCellWithIdentifier:#"myIdentifier"];
if (cell == nil)
{
// We failed to recycle a previously created cell, so we have no choice to allocate a new one
cell = [[[UITableViewCell alloc] initWithStyle:... reuseIdentifier:#"myIdentifier"] autorelase];
// As we just created the cell, we configure everything that will be common to every cell
// and that won't change even if the cell is reused later when you scroll
// e.g. text color, text font, accessoryType, ...
cell.textLabel.textColor = [UIColor blueColor];
...
}
// Now we got here either with a brand new cell that have just been created…
// … or after reusing an old cell that were not onscreen and has been recycled
// So THIS IS THE PLACE to configure everything that is SPECIFIC to each cell
// namely cell text, especially
cell.textLabel.text = [yourDataArray objectAtIndex: indexPath.row];
return cell;
}