Really bad performance with scrolling in UITableView with subviews - ios

I'm just not getting what is going on here.
I have a UITableView where each cell contain some subviews and it works fine and all. Unfortunately, the performance is horrendous, scrolling is just way too choppy. I read that maybe you can subclass UITableViewCell and that could help performance, but I'm not sure on how to that or implement another solution that would fix the issue.
I've posted the delegate method for the tableView below, any help would be greatly appreciated!
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UIImageView* imageView;
UILabel* ttitle;
UILabel* ttitle2;
UILabel* ttitle3;
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
// Configure cell:
// *** This section should configure the cell to a state independent of
// whatever row or section the cell is in, since it is only executed
// once when the cell is first created.
imageView=[[UIImageView alloc]initWithFrame:CGRectMake(10.0, 11.0, 50.0, 50.0)];
[imageView setContentMode:UIViewContentModeScaleAspectFill];
imageView.layer.masksToBounds=YES;
imageView.layer.cornerRadius=5.0;
imageView.tag=1;
[cell.contentView addSubview:imageView];
ttitle = [[[UILabel alloc] initWithFrame:CGRectMake(70.0, 7.0, 200, 20)] autorelease];
ttitle.textColor= [UIColor blackColor];
ttitle.numberOfLines=1;
ttitle.tag=69;
ttitle.backgroundColor=[UIColor clearColor];
ttitle.font=[UIFont fontWithName:#"Arial Bold" size:15.0];
[cell.contentView addSubview:ttitle];
if (indexPath.row==0) {
CGSize size=[[[data objectAtIndex:indexPath.row] valueForKey:#"content"] sizeWithFont:[UIFont systemFontOfSize:14.0f] constrainedToSize:CGSizeMake(265.0f, CGFLOAT_MAX) lineBreakMode:NSLineBreakByWordWrapping];
ttitle2 = [[[UILabel alloc] initWithFrame:CGRectMake(70.0, 27.5, 200, size.height)] autorelease];
ttitle2.textColor= [UIColor darkGrayColor];
ttitle2.backgroundColor=[UIColor clearColor];
ttitle2.numberOfLines=0;
ttitle2.tag=70;
ttitle2.textAlignment = NSTextAlignmentLeft;
ttitle2.lineBreakMode=NSLineBreakByWordWrapping;
ttitle2.font=[UIFont fontWithName:#"Arial" size:14.0];
[cell.contentView addSubview:ttitle2];
ttitle3 = [[[UILabel alloc] initWithFrame:CGRectMake(70.0, ttitle2.frame.origin.y+ttitle2.frame.size.height-8.0, 210, 40)] autorelease];
ttitle3.textColor= [UIColor darkGrayColor];
ttitle3.backgroundColor=[UIColor clearColor];
ttitle3.numberOfLines=1;
ttitle3.tag=71;
ttitle3.textAlignment = NSTextAlignmentLeft;
ttitle3.lineBreakMode=NSLineBreakByWordWrapping;
ttitle3.font=[UIFont fontWithName:#"Arial" size:11.0];
[cell.contentView addSubview:ttitle3];
}
else{
CGSize size=[[[data objectAtIndex:indexPath.row] valueForKey:#"content"] sizeWithFont:[UIFont systemFontOfSize:14.0f] constrainedToSize:CGSizeMake(265.0f, CGFLOAT_MAX) lineBreakMode:NSLineBreakByWordWrapping];
ttitle2 = [[[UILabel alloc] initWithFrame:CGRectMake(70.0, 27.0, 200, size.height)] autorelease];
ttitle2.textColor= [UIColor darkGrayColor];
ttitle2.backgroundColor=[UIColor clearColor];
ttitle2.numberOfLines=0;
ttitle2.tag=70;
ttitle2.textAlignment = NSTextAlignmentLeft;
ttitle2.lineBreakMode=NSLineBreakByWordWrapping;
ttitle2.font=[UIFont fontWithName:#"Arial" size:14.0];
[cell.contentView addSubview:ttitle2];
ttitle3 = [[[UILabel alloc] initWithFrame:CGRectMake(70.0, ttitle2.frame.origin.y+ttitle2.frame.size.height-9.0, 210, 40)] autorelease];
ttitle3.textColor= [UIColor darkGrayColor];
ttitle3.backgroundColor=[UIColor clearColor];
ttitle3.numberOfLines=1;
ttitle3.tag=71;
ttitle3.textAlignment = NSTextAlignmentLeft;
ttitle3.lineBreakMode=NSLineBreakByWordWrapping;
ttitle3.font=[UIFont fontWithName:#"Arial" size:11.0];
[cell.contentView addSubview:ttitle3];
}
}
else {
imageView = (UIImageView *) [cell viewWithTag:1];
ttitle=( UILabel *) [cell viewWithTag:69];
ttitle2=( UILabel *) [cell viewWithTag:70];
ttitle3=( UILabel *) [cell viewWithTag:71];
}
//STUFFOUTSIDE
// Customize cell:
// *** This section should customize the cell depending on what row or section
// is passed in indexPath, since this is executed every time this delegate method
// is called.
imageView.image=[UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:[[data objectAtIndex:indexPath.row] valueForKey:#"thumbnail"]]]];
[ttitle setText:[[data objectAtIndex:indexPath.row] valueForKey:#"name"]];
[ttitle2 setText:[[data objectAtIndex:indexPath.row] valueForKey:#"content"]];
NSString* first=[[[data objectAtIndex:indexPath.row] valueForKey:#"hashtag"] stringByAppendingString:#" "];
NSString* second =[first stringByAppendingString:[[data objectAtIndex:indexPath.row] valueForKey:#"place"]];
NSString* third=[second stringByAppendingString:#" "];
NSString* fourth=[third stringByAppendingString:#"ยค "];
NSString* conversion=[[[data objectAtIndex:indexPath.row] valueForKey:#"counter"] stringValue];
NSString* fifth=[fourth stringByAppendingString:conversion];
[ttitle3 setText:fifth];
return cell;
}

You're synchronously fetching data from an URL for getting the image for each cell. This means that for each cell you're blocking the main thread until the data has been fetched from the internet.
You'll have to do the image loading asynchronously on a background thread and update the cells when the image is loaded. There are plenty of blog posts about this.
Update:
There's no way to tell whether the image URL is local or not, but I assume that it's a remote URL and the images are not stored inside your app.

There are a lot of issues that can cause lag but I see three probable causes in this case:
The background color of cell subviews (your labels, etc) shouldn't be clear unless absolutely required. This kills scrolling performace.
If the image being set in the imageView is not the right size and has to be scaled, this will cause major lag. If this is the case, you will either need to save an appropriately sized image to display in the table, or load them asynchronously so that the table will scroll without waiting for the image to load.
As Fabian mentions in the comment below, since you are downloading these images from the web, you definitely want to load the images asynchronously. Every time that a cell is displayed, it has to wait for the image to download before moving onto displaying the next one. This is the biggest problem that you have with this code right now. The following question has a few different options for doing this: iOS - Asynchronous Image Downloading

Related

Same Cells repeat after Scrolling

I am using table view using custom coding with tag method to save memory.
I was successful to show data in the view but the problem is if 10 cells are showing and then if I scroll down like for one cell then it should show 2-11 cell data but it switches to 1-10 again.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellIdentifier = #"cellID";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
UILabel *cellNAMElabl = nil;
UILabel *cellDetaillabl = nil;
UIImageView *imgView = nil;
if (cell == nil) {
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:cellIdentifier];
cellNAMElabl = [[UILabel alloc] initWithFrame:CGRectMake(88, 10, 150, 20)];
[cellNAMElabl setTag:1];
cellNAMElabl.text = [name5 objectAtIndex:indexPath.row];
UIFont *myFont1 = [ UIFont fontWithName: #"Arial" size: 20.0 ];
cellNAMElabl.font = myFont1;
[cell.contentView addSubview:cellNAMElabl];
cellDetaillabl = [[UILabel alloc] initWithFrame:CGRectMake(88, 28, 150, 20)];
[cellDetaillabl setTag:2];
cellDetaillabl.text = [email5 objectAtIndex:indexPath.row];
UIFont *myFont = [ UIFont fontWithName: #"Arial" size: 13.0 ];
cellDetaillabl.font = myFont;
[cell.contentView addSubview:cellDetaillabl];
imgView=[[UIImageView alloc] initWithFrame:CGRectMake(25, 5, 52, 50)];
[imgView setTag:3];
imgView.image = [imagepath5 objectAtIndex:indexPath.row];
[cell.contentView addSubview:imgView];
}
cellNAMElabl = (UILabel *)[cell viewWithTag:1];
cellDetaillabl = (UILabel*)[cell viewWithTag:2];
imgView = (UIImageView*)[cell viewWithTag:3];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
return cell;
}
You are not assigning new content to subviews, if they have been already created. After the case if(cell == nil), these you have just got references.
cellNAMElabl = (UILabel *)[cell viewWithTag:1];
cellDetaillabl = (UILabel*)[cell viewWithTag:2];
imgView = (UIImageView*)[cell viewWithTag:3];
Here when cell is not nil, you are just getting references to labels and imageview, but you are not setting new text and image from data source. Add following lines and remove them from the if (cell == nil) part:
cellNAMElabl.text = [name5 objectAtIndex:indexPath.row];
cellDetaillabl.text = [email5 objectAtIndex:indexPath.row];
imgView.image = [imagepath5 objectAtIndex:indexPath.row];
[cell.contentView addSubview:imgView];
The way this dequeueReusableCellWithIdentifier works: If iOS detects that a cell is not displayed anymore, then dequeueReusableCellWithIdentifier will return that cell. If there is no unused cell, it returns nil. So what you need to do:
If dequeueReusableCellWithIdentifier returns nil, then you create a new cell, and you do all the setup that is required for all cells with the same identifier. For example, add view tags like you did, set fonts, colors etc.
Then, whether you use a cell returned by dequeueReusableCellWithIdentifier or one that you just created yourself, you add all the information that is used for the specific section/row that you want to display. So if row 1, row2, and so on display different text, then you set the text here. That's what you didn't do, so when a cell was reused, you didn't set the new text for it.
So the idea is that all the work that is the same for all rows is only done once when a cell is created, and only as many cells are created as is needed to display them on the screen. The work that is different from row to row is done for each row, as it is needed.
If you set a breakpoint in the if cell == nil block its probably only being hit for the first set if your reuseID is correct. Thats why its never getting a chance to set any new data into the cell.
You should not look for a nil cell, rather use a correct reuseID and a prototype cell in IB that is set to a custom UITableViewCell subclass you create.
Its also good practice to implement prepareForReuse on custom cells, where you clear any cell data e.g. label.text = nil, imageview.image = nil
This way you dont get invalid data from previously dequeued cells. It might not solve the question directly, but it would have wiped the fixed data set in your if cell == nil block to help debug.
What you want to do is..
add/setup the tableViewCell UI if the cell is nil..
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellIdentifier = #"cellID";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:cellIdentifier];
UILabel *cellNAMElabl = [[UILabel alloc] initWithFrame:CGRectMake(88, 10, 150, 20)];
cellNAMElabl.tag = 1;
cellNAMElabl.font = [UIFont fontWithName: #"Arial" size: 20.0 ];
[cell.contentView addSubview:cellNAMElabl];
UILabel *cellDetaillabl = [[UILabel alloc] initWithFrame:CGRectMake(88, 28, 150, 20)];
cellDetaillabl.tag = 2;
cellDetaillabl.font = [UIFont fontWithName: #"Arial" size: 13.0 ];
[cell.contentView addSubview:cellDetaillabl];
UIImageView *imgView=[[UIImageView alloc] initWithFrame:CGRectMake(25, 5, 52, 50)];
imgView.tag = 3;
[cell.contentView addSubview:imgView];
}
//and just update your data if the cell is currently exist and not nil..
//you already called the view using tag so, you dont need those:
// UILabel *cellNAMElabl = nil;
// UILabel *cellDetaillabl = nil;
// UIImageView *imgView = nil;
((UILabel *)[cell viewWithTag:1]).text = [name5 objectAtIndex:indexPath.row]; // cellNAMElabl
((UILabel*)[cell viewWithTag:2]).text = [email5 objectAtIndex:indexPath.row]; // cellDetaillabl
((UIImageView*)[cell viewWithTag:3]).image = [imagepath5 objectAtIndex:indexPath.row]; // imgView
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
return cell;
}
hope this have help you, happy coding cheers!

How to disable reloading tableview when scrolling in iOS

I want to disable reloading table view when scrolling. Now, my app when user scroll the uitableview, cellForRowAtIndexPath has been recalled. How can I disable it when srcolling? Please give me some advice. Thanks in advance.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *CellIdentifier = [NSString stringWithFormat:#"%d,%d",indexPath.section,indexPath.row];
UITableViewCell *cell = [_tableView dequeueReusableCellWithIdentifier:CellIdentifier];
UILabel *FileNameLabel;
UILabel *UploadTimeLabel;
if (cell == nil)
{
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
CFileNameLabel = [[UILabel alloc] initWithFrame:CGRectMake(40, 0, 130, 30)];
UploadTimeLabel = [[UILabel alloc] initWithFrame:CGRectMake(40, 20, 130, 25)];
FileNameLabel.tag = 1000;
FileNameLabel.backgroundColor = [UIColor clearColor];
FileNameLabel.font = [UIFont fontWithName:#"Helvetica" size:14];
FileNameLabel.font = [UIFont boldSystemFontOfSize:14];
FileNameLabel.textColor = [UIColor blackColor];
// FileNameLabel.text =[temp objectAtIndex:indexPath.row];
[cell.contentView addSubview: FileNameLabel];
[FileNameLabel release];
UploadTimeLabel.tag = 2000;
UploadTimeLabel.backgroundColor = [UIColor clearColor];
UploadTimeLabel.font = [UIFont fontWithName:#"Helvetica" size:12];
UploadTimeLabel.textColor = [UIColor grayColor];
// UploadTimeLabel.text = [UploadTimeArray objectAtIndex:indexPath.row];
[cell.contentView addSubview: UploadTimeLabel];
[UploadTimeLabel release];
}
if( [OriginalArray count] > 0)
{
UILabel *fileNameLbl = (UILabel*)[cell.contentView viewWithTag:1000];
//fileNameLbl.text =[temp objectAtIndex:indexPath.row];
fileNameLbl.text =[[OriginalArray valueForKey:#"FILENAME"] objectAtIndex:indexPath.row];
UILabel *uploadlbl = (UILabel*)[cell.contentView viewWithTag:2000];
uploadlbl.text =[[OriginalArray valueForKey:#"UPLOADTIME"] objectAtIndex:indexPath.row];
}
_tableView.contentInset = UIEdgeInsetsMake(0, 0, 0, 0);
return cell;
}
You cannot block the cellForRowAtIndexPath: from calling when scrolling the tableview. If something need not happen every time, You may keep it in if condition.
if (cell == nil)
{
//Functionality goes here when it not needed to happen every time.
}
Do not implement the method UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"yourID"]; or UITableViewCell *cell = [tableView dequeueCellWithReuseIdentifier:nil];
It will prevent the table view from reusing the cell. But its not a good idea if your tableview is going to contain large number of cell. Hope this helps. :)
Instead of trying to avoid being reloaded, maybe you could play with your data source, so that it appears as the data doesn't change. I hope you understand what I mean.
use dequecellforrowatindex method to avoid cell reloading.

How to optimize cellForRowAtIndexPath: code

After adding a font and a shadow to some UILabels I noticed that the table view animation lags when the view is popped off the stack (a side swipe like FB/Path uses). The side swipe was smooth until I added the UILabel shadows.
I think I might be adding it it the wrong place so that the label properties are being added incorrectly maybe. Please take a look at the following cellForRowAtIndexPath: method below:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString * cellReuseIdentifier = #"cellReuseIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellReuseIdentifier];
if (cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellReuseIdentifier];
}
UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 2, self.view.bounds.size.width, 200)];
imageView.image = [UIImage imageNamed:#"rest.jpg"];
[cell.contentView addSubview:imageView];
UILabel *titleLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 2, 320, 30)];
titleLabel.text = (NSString *)[[publicDataArray objectAtIndex:indexPath.row] objectForKey:#"title"];
titleLabel.backgroundColor = [UIColor clearColor];
titleLabel.textColor = [UIColor whiteColor];
[titleLabel setFont:[UIFont fontWithName:#"HelveticaNeue" size:24]];
titleLabel.layer.shadowColor = [[UIColor whiteColor] CGColor];
titleLabel.layer.shadowOpacity = 0.7;
[cell.contentView addSubview:titleLabel];
UILabel *detailLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 160, cell.bounds.size.width, 30)];
detailLabel.text = (NSString *)[[publicDataArray objectAtIndex:indexPath.row] objectForKey:#"description"];
detailLabel.backgroundColor = [UIColor clearColor];
detailLabel.textColor = [UIColor whiteColor];
[detailLabel setFont:[UIFont fontWithName:#"HelveticaNeue" size:18]];
detailLabel.layer.shadowColor = [[UIColor whiteColor] CGColor];
detailLabel.layer.shadowOpacity = 0.7;
[cell.contentView addSubview:detailLabel];
cell.contentView.backgroundColor = [UIColor clearColor];
return cell;
}
thanks for any help.
You're always adding new subviews. So whenever you scroll the table view your cells are getting more and more content added into them.
Create all your subviews when the cell is created and then just update the subviews settings. Something like:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString * cellReuseIdentifier = #"cellReuseIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellReuseIdentifier];
if (cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellReuseIdentifier];
UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 2, self.view.bounds.size.width, 200)];
imageView.tag = 123123;
[cell.contentView addSubview:imageView];
UILabel *titleLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 2, 320, 30)];
titleLabel.tag = 234234];
titleLabel.backgroundColor = [UIColor clearColor];
titleLabel.textColor = [UIColor whiteColor];
[titleLabel setFont:[UIFont fontWithName:#"HelveticaNeue" size:24]];
titleLabel.layer.shadowColor = [[UIColor whiteColor] CGColor];
titleLabel.layer.shadowOpacity = 0.7;
[cell.contentView addSubview:titleLabel];
UILabel *detailLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 160, cell.bounds.size.width, 30)];
detailLabel.tag = 345345];
detailLabel.backgroundColor = [UIColor clearColor];
detailLabel.textColor = [UIColor whiteColor];
[detailLabel setFont:[UIFont fontWithName:#"HelveticaNeue" size:18]];
detailLabel.layer.shadowColor = [[UIColor whiteColor] CGColor];
detailLabel.layer.shadowOpacity = 0.7;
[cell.contentView addSubview:detailLabel];
cell.contentView.backgroundColor = [UIColor clearColor];
}
UIImageView *imageView = (UIImageView *)[cell viewWithTag:123123];
imageView.image = [UIImage imageNamed:#"rest.jpg"];
UILabel *titleLabel = (UILabel *)[cell viewWithTag:234234];
titleLabel.text = (NSString *)[[publicDataArray objectAtIndex:indexPath.row] objectForKey:#"title"];
UILabel *detailLabel = (UILabel *)[cell viewWithTag:345345];
detailLabel.text = (NSString *)[[publicDataArray objectAtIndex:indexPath.row] objectForKey:#"description"];
return cell;
}
Since text attributes never change, move the code that sets them inside the if statement. Keep only the code that sets the image and the text of your labels outside the if statement. Cells are reused, so the attributes such as font etc. will remain with the cell even after it gets "recycled". In the else branch add code that finds existing labels in the cell. Otherwise, you keep adding the same label to the cell multiple times.
You add subviews, even after dequeueing instead of initializing a new cell. Make sure all the code that creates and adds subviews are only done on initializing a cell. If you need to refer to views in the cell for configuring, subclass UITableViewCell.
Also, shadow rendering could be slowing it down too, add a shadowpath to make the rendering more efficient:
add to your tableView:cellForRowAtIndexPath: method:
...
CGPathRef shadowPath = [UIBezierPath bezierPathWithRect:detailLabel.layer.bounds].CGPath;
detailLabel.layer.shadowPath = shadowPath;
...
This article from Twitter Engineering gives you a great overview: http://engineering.twitter.com/2012/02/simple-strategies-for-smooth-animation.html
Basically, you want to avoid using subviews but instead draw your content directly with Quartz. It's the single best thing you can do to improve performance. Also: Avoid transparency! In Instruments, you can also use the Core Animation instrument and activate "Color Blended Layers" to see where transparent views are being composed:
Replace your code with this :
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString * cellReuseIdentifier = #"cellReuseIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellReuseIdentifier];
if (cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellReuseIdentifier];
UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 2, self.view.bounds.size.width, 200)];
imageView.image = [UIImage imageNamed:#"rest.jpg"];
imageView.tag =1;
[cell.contentView addSubview:imageView];
UILabel *titleLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 2, 320, 30)];
titleLabel.text = (NSString *)[[publicDataArray objectAtIndex:indexPath.row] objectForKey:#"title"];
titleLabel.backgroundColor = [UIColor clearColor];
titleLabel.tag = 2;
titleLabel.textColor = [UIColor whiteColor];
[titleLabel setFont:[UIFont fontWithName:#"HelveticaNeue" size:24]];
titleLabel.layer.shadowColor = [[UIColor whiteColor] CGColor];
titleLabel.layer.shadowOpacity = 0.7;
[cell.contentView addSubview:titleLabel];
UILabel *detailLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 160, cell.bounds.size.width, 30)];
detailLabel.tag = 3;
detailLabel.text = (NSString *)[[publicDataArray objectAtIndex:indexPath.row] objectForKey:#"description"];
detailLabel.backgroundColor = [UIColor clearColor];
detailLabel.textColor = [UIColor whiteColor];
[detailLabel setFont:[UIFont fontWithName:#"HelveticaNeue" size:18]];
detailLabel.layer.shadowColor = [[UIColor whiteColor] CGColor];
detailLabel.layer.shadowOpacity = 0.7;
}
UIImageView *tempImgView = (UIImageView *)[cell viewWithTag:1];
tempImgView.image = [UIImage imageNamed:#""];// Here you can set any image by reusing imageview without allocating again and again
UILabel *tempLabel;
tempLabel = (UILabel *)[cell viewWithTag:2];
tempLabel.text = #"";// Here you can access your title label and can set its properties without allocating again
tempLabel = (UILabel *)[cell viewWithTag:3];
tempLabel.text = #"";// Here you can access your detailLabel label and can set its properties without allocating again
[cell.contentView addSubview:detailLabel];
cell.contentView.backgroundColor = [UIColor clearColor];
return cell;
}
You need create custom table view cell with a class. This code you added many label then shadow show no correctly.
code like this.
(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString * cellReuseIdentifier = #"cellReuseIdentifier";
UITableCustomViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellReuseIdentifier];
if (cell == nil)
{
cell = [[UITableCustomViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellReuseIdentifier];
}
cell.imageView.image = [UIImage imageNamed:#"rest.jpg"];
cell.titleLabel.text = (NSString *)[[publicDataArray objectAtIndex:indexPath.row] objectForKey:#"title"];
cell.detailLabel.text = (NSString *)[[publicDataArray objectAtIndex:indexPath.row] objectForKey:#"description"];
return cell;
}

How to set selected background color of UITableViewCell when not in UITableView

I don't see why this would matter, but I'm having some trouble getting it to work.
Disclaimer: This is my first iOS app (or ANY Apple development for that matter, and the app needs to be done yesterday, so excuse any rushed-looking code please).
I'm using the SWRevealViewController library to create a Facebook-esque "side view" when a button on the home view navigation controller is clicked. It works great, love it. This view holds a UITableView with only two static cells, and I just received a request to add a cell to the very bottom of the view.
It didn't seem obvious to try to get that third cell "in" the UITableView, so in my xib I just created a UITableViewCell outside of the UITableView, and put it at the bottom of the view. It then hooked it up to my controller using the standard IBOutlet workflow.
Back in my viewDidLoad I skinned the rogue cell to look like the rest of the tablecells, added some wording, added a handler to make it open up my company's website when clicked, and all of that works fine. I did all of this stuff for the "regular" table cells in my tableView:cellForRowAtIndexPath function.
BUT for some reason when I click on the cell, it's not being highlighted like my other regular cells when I click on it! Why!
CODE:
- (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];
} else {
[[cell.contentView viewWithTag:1] removeFromSuperview];
}
UILabel *lblView = [[UILabel alloc] initWithFrame:CGRectMake(20.0, 3.0, 187.0, cell.frame.size.height)];
[lblView setFont:[UIFont fontWithName:#"FuturaStd-Bold" size:12]];
lblView.textColor = [UIColor colorWithRed:(255/255.f) green:(241/255.f) blue:(204/255.f) alpha:1.0];
lblView.tag = 1;
if (indexPath.row == 0){
[lblView setText:#"SCHEDULE"];
} else if (indexPath.row == 1){
[lblView setText:#"SPEAKERS"];
}
lblView.backgroundColor=[UIColor clearColor];
[cell.contentView addSubview:lblView];
UIImageView *av = [[UIImageView alloc] initWithFrame:CGRectMake(20, 20, 277, 58)];
av.backgroundColor = [UIColor clearColor];
av.opaque = NO;
av.image = [UIImage imageNamed:#"blackBar.png"];
cell.backgroundView = av;
UIView *bgColorView = [[UIView alloc] init];
[bgColorView setBackgroundColor:[UIColor colorWithRed:(240/255.f) green:(145/255.f) blue:(62/255.f) alpha:1.0]];
[cell setSelectedBackgroundView:bgColorView];
return cell;
}
The above code works fine for my "regular cells". That last bit before I return the cell is what sets the background highlight a weird orange color when it's "being clicked".
The code below is the SAME THING but in my viewDidLoad, and it's not setting the background highlight color when being clicked.
- (void)viewDidLoad
{
[super viewDidLoad];
//... stuff
UILabel *lblView = [[UILabel alloc] initWithFrame:CGRectMake(20.0, 3.0, 187.0, _roguecell.frame.size.height)];
[lblView setFont:[UIFont fontWithName:#"FuturaStd-Bold" size:12]];
lblView.textColor = [UIColor colorWithRed:(255/255.f) green:(241/255.f) blue:(204/255.f) alpha:1.0];
[lblView setText:#"IT'S A SECRET LOL"];
lblView.backgroundColor=[UIColor clearColor];
[_roguecell.contentView addSubview:lblView];
UIImageView *av = [[UIImageView alloc] initWithFrame:CGRectMake(20, 20, 277, 58)];
av.backgroundColor = [UIColor clearColor];
av.opaque = NO;
av.image = [UIImage imageNamed:#"blackBar.png"];
_roguecell.backgroundView = av;
UIView *bgColorView = [[UIView alloc] init];
[bgColorView setBackgroundColor:[UIColor colorWithRed:(240/255.f) green:(145/255.f) blue:(62/255.f) alpha:1.0]];
[_roguecell setSelectedBackgroundView:bgColorView];
UITapGestureRecognizer *singleFingerTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(handleSingleTap:)];
[_roguecell addGestureRecognizer:singleFingerTap];
}
Maybe it has something to do with my xib file I have the UITableView extending down the entire view, and the rogue UITableViewCell "on top" of it (but not in it obviously). I tried messing around with the locations of the table and the cell, but that didn't do anything.
Thanks for reading.
I ended up removing my rogue UITableViewCell, and upping the total number of cells in my UITableView from 2 to 4. The 3rd cell I removed my custom background from, didn't add any text to, disabled user interaction from, and set the height using the - (CGFloat) tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath method to fill up the rest of the table leaving only enough room at the bottom for my "footer" cell.

How to load images asynchronously in uitableview without memory warning?

Hi iam developing an app where i will fetch images from web service and load the images in tableview. I loaded the images asynchronously. The problem is my app get crash while scrolling the tableview and in log it shows memory recieved warning.Also same images gets repeated in many rows.Also it takes more time to load. i used the below code.
- (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];
/* UILabel * cellLabel=[[UILabel alloc] initWithFrame:CGRectMake(0, 50, cell.frame.size.width-20, 45)];
cellLabel.textColor=[UIColor blackColor];
cellLabel.backgroundColor=[UIColor clearColor];
cellLabel.tag=2;
[cell.contentView addSubview:cellLabel];*/
cell.selectionStyle=UITableViewCellSelectionStyleNone;
cell.backgroundView=[[UIImageView alloc] initWithImage:[UIImage imageNamed:#"list_iPhone.png"]];
UIImageView *imv = [[UIImageView alloc]initWithFrame:CGRectMake(10,18, 48, 48)];
imv.tag=4;
imv.image=[UIImage imageNamed:#"ImagePlaceholder.png"];
[cell.contentView addSubview:imv];
UIImageView *arrwimv = [[UIImageView alloc]initWithFrame:CGRectMake(260,35, 14, 17)];
arrwimv.image=[UIImage imageNamed:#"arrw_iPhone.png"];
[cell.contentView addSubview:arrwimv];
UILabel *descriptionLbl=[[UILabel alloc] initWithFrame:CGRectMake(100, 27, 450, 45)];
descriptionLbl.font=[UIFont CITY311_TitleFontWithSize:18];
descriptionLbl.tag=1;
descriptionLbl.textAlignment=UITextAlignmentLeft;
descriptionLbl.textColor=[UIColor blackColor];
descriptionLbl.backgroundColor=[UIColor clearColor];
[cell.contentView addSubview:descriptionLbl];
UILabel *descriptionLbl2=[[UILabel alloc] initWithFrame:CGRectMake(100, 5, 450, 45)];
descriptionLbl2.font=[UIFont CITY311_TitleFontWithSize:18];
descriptionLbl2.tag=2;
descriptionLbl2.textAlignment=UITextAlignmentLeft;
descriptionLbl2.textColor=[UIColor blackColor];
descriptionLbl2.backgroundColor=[UIColor clearColor];
[cell.contentView addSubview:descriptionLbl2];
}
UIImageView *imv2=(UIImageView *)[cell.contentView viewWithTag:4];
dispatch_async(mainQueue, ^(void) {
if(![[[issueArray objectAtIndex:indexPath.row]objectForKey:#"PhotoUrl"] isEqualToString:#""])
{
NSData *imageData = [[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:[[issueArray objectAtIndex:indexPath.row]objectForKey:#"PhotoUrl"]]];
UIImage* image = [[UIImage alloc] initWithData:imageData];
imv2.image = image;
}
});
UILabel *lbl=(UILabel *)[cell.contentView viewWithTag:1];
lbl.text=[[issueArray objectAtIndex:indexPath.row] objectForKey:#"issueSubmittedDate"];
UILabel *lbl2=(UILabel *)[cell.contentView viewWithTag:2];
lbl2.text=[[issueArray objectAtIndex:indexPath.row] objectForKey:#"IssueName"];
return cell;
}
In view did load
mainQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
In .h file
dispatch_queue_t mainQueue;
Please help to load the images properly without any memory warning(Crash).Thanks in Advance.
you are reusing tableviewcells. When a cell moves off the screen, it will be set aside so that you can reuse the object. When you are doing a dequeueReusableCellWithIdentifier you can get a 'old' cell that already contains an image. If you dont' clear the data from that cell you will see the old data (image) until the new image is downloaded.
inside the if(cell==nil) you should only create the cell and set properties that will be the same for every row. Set and clear the data below that if.
The crashes probably happen because a cell can be moved out of the view and reused for an other row before the initial callback is ready. Try setting the identifier to a unique value. Something like:
NSString *CellIdentifier = [NSString stringWithFormat:#"Cell%d", indexPath.Row];
Only keep your code like that when the number of rows is low. Otherwise you could get memory problems.
Instead of trying to fix it yourself, you could try using something like https://github.com/rs/SDWebImage

Resources