Slow Scrolling UITableView? - iphone

My UITableView, after the messages (content) is loaded into the cells, experiences a very noticeable lag in scrolling and sometimes freezes up for a few seconds. This is weird because all the messages are loaded once the user scrolls. Any ideas on how to make this fast scrolling no problem?
Thank you!
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *simpleTableIdentifier = #"MailCell";
MailCell *cell = (MailCell *)[tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell == nil)
{
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"MailCell" owner:self options:nil];
cell = [nib objectAtIndex:0];
// Anything that should be the same on EACH cell should be here.
UIView *myBackView = [[UIView alloc] initWithFrame:cell.frame];
myBackView.backgroundColor = [UIColor colorWithRed:40.0/255.0 green:148.0/255.0 blue:196.0/255.0 alpha:1];
cell.selectedBackgroundView = myBackView;
cell.messageText.textAlignment = NSTextAlignmentLeft;
cell.messageText.lineBreakMode = NSLineBreakByTruncatingTail;
}
NSUInteger row = [indexPath row];
// Extract Data
// Use the message object instead of the multiple arrays.
CTCoreMessage *message = [[self allMessages] objectAtIndex:row];
// Sender
CTCoreAddress *sender = [message sender];
NSString *senderName = [sender name];
// Subject
NSString *subject = [message subject];
if ([subject length] == 0)
{
subject = #"(No Subject)";
}
// Body
BOOL isPlain = YES;
NSString *body = [message bodyPreferringPlainText:&isPlain];
body = [[body componentsSeparatedByCharactersInSet:
[NSCharacterSet whitespaceAndNewlineCharacterSet]]
componentsJoinedByString:#" "];
body = [body stringByReplacingOccurrencesOfString:#" " withString:#" "];
// Populate Cell
[[cell nameText] setText:senderName];
[[cell subjectField] setText:subject];
[[cell messageText] setText:body];
if ([message isUnread])
{
cell.nameText.textColor = [UIColor colorWithRed:15.0/255.0 green:140.0/255.0 blue:198.0/255.0 alpha:1];
}
else
{
cell.nameText.textColor = [UIColor blackColor];
}
return cell;
}

xCode comes with a profiler called Instruments. It's CPU time profiler is perfect for figuring out which code is slowing things down. Run your app with the profiler and spend a few seconds just scrolling around. It will give you statistics.
Keep in mind, the code inside if (cell == nil) will run about 10 times (UITableView caches just enough cells to fill itself). But the code outside the if is expensive - it runs every time a cell becomes visible.
I would guess the most expensive operations in the code you posted are:
Giving iOS too many subviews to draw on a cell
Do your own drawing instead.
Replacing runs of whitespace in the entire body text with single spaces
The code you posted allocates new strings for each word, plus an array to hold them. Then it allocates two more copies (one with words rejoined and one with runs of spaces compacted). It processes the entire body text string, even if the majority will never be visible to the user in a tiny preview of the body!
Cache the resulting string so that this operation is performed only once per cell.
Also, you can create a new mutable string, reserve space in it, and copy characters from the original in a loop (except runs of whitespace). Instead of processing the entire body text, you could stop at 100 characters or so (enough to fill a table cell). Faster and saves memory.
Slow UITableView scrolling is a very very common question. See:
How to solve slow scrolling in UITableView
iPhone UITableView stutters with custom cells. How can I get it to scroll smoothly?

Nothing seems wrong with your code. I'd recommend using a table optimization framework such as the free Sensible TableView.

Related

Ugly heightForRowAtIndexPath and cellForRowAtIndexPath

I have a UItableview, which I'm populating with data, using heightForRowAtIndexPath and cellForRowAtIndexPath. Apparently Apple makes me do things in my code twice.
First I have to calculate the size of my views (for that I have to make them) in heightForRowAtIndexPath and then I have to make them again, to add them to the actual view.
I have a pretty complicated view, so it looks double ugly, when you have to write it twice.
Isn't there a better way to do this?
UPDATE
This is how my code looks. It's not totally the same, but pretty close. Why in the world does apple make me write this twice?
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
NSLog(#"heightForRowAtIndexPath");
//Initiating strings
NSString *headlineString;
NSString *subHeadlineString;
NSString *bylineString;
if (global.magazine.issues.count==0) {
return 45;
}else if(indexPath.section == global.magazine.issues.count+1) {
//Finding the right issue and article for this row
Issue *issue = [global.magazine.issues objectAtIndex:global.magazine.issues.count-1];
//Creating the headline
headlineString = [NSString stringWithFormat:#"<span class='bold_style'>FOREWORD</span>"];
//Creating the subHeadline
subHeadlineString = [NSString stringWithFormat:#"%#", [issue.magazine_foreword substringToIndex:100]];
//Creating byline
bylineString = [[NSString stringWithFormat:#"<span class='ital_style'>By %#</span>", issue.magazine_byline] capitalizedString];
}else{
//Finding the right issue and article for this row
Issue *issue = [global.magazine.issues objectAtIndex:indexPath.section-1];
Article *article = [issue.articles objectAtIndex:indexPath.row];
//Creating the headline
headlineString = [NSString stringWithFormat:#"<span class='bold_style'>%#</span>", [article.title uppercaseString]];
//Creating the subHeadline
subHeadlineString = [NSString stringWithFormat:#"%#", [article.main_text substringToIndex:100]];
//Creating byline
bylineString = [NSString stringWithFormat:#"<span class='ital_style'>By %#</span>", article.byline];
}
//Creating the labels
NMCustomLabel *headline = [global.label headLineLabelWithString:headlineString fromTop:30 withWidth:global.screenWidth-60];
NMCustomLabel *subHeadline = [global.label subHeadlineLabelWithString:subHeadlineString fromTop:30+headline.height+10 withWidth:global.screenWidth-60];
NMCustomLabel *byline = [global.label articleBylineLabelWithString:bylineString fromTop:30+headline.height+10+subHeadline.height+10 withWidth:global.screenWidth-60];
//Setting the height of the row
return 30+headline.height+10+subHeadline.height+10+byline.height+30;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
NSLog(#"cellForRowAtIndexPath");
//Preparing the cell
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
if (cell == nil) {
cell = [[UITableViewCell alloc]
initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:CellIdentifier];
}
//Removing former text views
for (UIView *subview in [cell subviews]) {
if (subview.tag == 21 || subview.tag == 22 || subview.tag == 23) [subview removeFromSuperview];
}
//Removing and setting tableview border
[[cell viewWithTag:30] removeFromSuperview];
UIView *rightBorder = [[UIView alloc] initWithFrame:CGRectMake(cell.width-1, 0, 1, cell.height)];
rightBorder.backgroundColor = global.lightGrey;
rightBorder.tag = 30;
[cell addSubview:rightBorder];
//Setting the seletion background color on the cells
UIView *bgColorView = [[UIView alloc] init];
bgColorView.backgroundColor = global.extraLightGrey;
cell.selectedBackgroundView = bgColorView;
if (global.magazine.issues.count==0) {
return cell;
}else if (indexPath.section-1 == global.magazine.issues.count) {
//Finding the right issue and article for this row
Issue *issue = [global.magazine.issues objectAtIndex:global.magazine.issues.count-1];
//Creating the headline
NSString *headlineString = [NSString stringWithFormat:#"<span class='bold_style'>FOREWORD</span>"];
NMCustomLabel *headline = [global.label headLineLabelWithString:headlineString fromTop:30 withWidth:global.screenWidth-60];
headline.tag = 21;
[cell addSubview:headline];
//Creating the subHeadline
NSString *subHeadlineString = [[NSString stringWithFormat:#"%#", issue.magazine_foreword] substringToIndex:100];
NMCustomLabel *subHeadline = [global.label subHeadlineLabelWithString:subHeadlineString fromTop:30+headline.height+10 withWidth:global.screenWidth-60];
subHeadline.tag = 22;
[cell addSubview:subHeadline];
//Creating byline
NSString *bylineString = [[NSString stringWithFormat:#"<span class='ital_style'>By %#</span>", issue.magazine_byline] capitalizedString];
NMCustomLabel *byline = [global.label articleBylineLabelWithString:bylineString fromTop:30+headline.height+10+subHeadline.height+10 withWidth:global.screenWidth-60];
byline.tag = 23;
[cell addSubview:byline];
}else{
//Finding the right issue and article for this row
Issue *issue = [global.magazine.issues objectAtIndex:indexPath.section-1];
Article *article = [issue.articles objectAtIndex:indexPath.row];
//Creating the headline
NSString *headlineString = [NSString stringWithFormat:#"<span class='bold_style'>%#</span>", [article.title uppercaseString]];
NMCustomLabel *headline = [global.label headLineLabelWithString:headlineString fromTop:30 withWidth:global.screenWidth-60];
headline.tag = 21;
[cell addSubview:headline];
//Creating the subHeadline
NSString *subHeadlineString = [NSString stringWithFormat:#"%#", [article.main_text substringToIndex:100]];
NMCustomLabel *subHeadline = [global.label subHeadlineLabelWithString:subHeadlineString fromTop:30+headline.height+10 withWidth:global.screenWidth-60];
subHeadline.tag = 22;
[cell addSubview:subHeadline];
//Creating byline
NSString *bylineString = [[NSString stringWithFormat:#"<span class='ital_style'>By %#</span>", article.byline] capitalizedString];
NMCustomLabel *byline = [global.label articleBylineLabelWithString:bylineString fromTop:30+headline.height+10+subHeadline.height+10 withWidth:global.screenWidth-60];
byline.tag = 23;
[cell addSubview:byline];
}
return cell;
}
The easiest solution is to follow DRY principles and either add height as a property of the objects you are using as a datasource or add a method to your view controller such as:
-(CGFloat)calculateHeightForHeadline:(NSString*)headline andSubHeadline:(NSString*)subHeadline andByLine:(NSString*)byLine
Then at least you only have the calculation code in one place.
Alternatively, you could call [tableView heightForRowAtIndexPath:indexPath] from your cellForRowAtIndexPath method
You have to do it twice because the table view needs to know how tall it is in total before it draws anything - so it calls the height method for every row before it calls any cell method. With your current code, depending on the number of rows, you may be experiencing a slight delay before the table appears - instruments will show you that it is the height method you're spending time in.
I don't know what you custom label classes do but you may be able to calculate the height without having to create views (which is expensive) by using the string or attributed string drawing and size calculation UIKit extensions, which were created for this exact purpose.
heightForRowAtIndexPath
Will be called for all your rows. This delegate method returns the height for your rows. As your design required different height for each rows depending upon the condition. Unfortunately you'll have to calculate the row height each time before your row gets created. It's like we are deciding just before drawing the row what will be it's hight.
There's one way you can avoid this. But I won't advice you to go for it. Because it'll change the design of your UITableView. What you can do is you can decide the maximum height of your row out of all the possible conditions you have. For eg. Let's consider it as 100 pixel. Then you can draw your rest of the cells. However, that'll leave empty space if any of your row is less then 100 pixel. And it'll look shaggy.
Basically, to meet your requirement you'll have to do this twice. No other choice :-(
I wonder, why are you creating your custom labels in heightForRowAtIndexpath? Why don't you just calculate the size of the text with sizeWithFont: or such methods? I think that would be a better way to calculate height of the row. Good Luck!

UITableView with custom cell scrolling slowly

I have three different cells. The Cell01, the Cell02 and the Cell03. The Cell01 must appear just one time, at the top of the tableview, and the rest, the 02 and 03 must interpolate (02, 03, 02, 03 (...)).
The problem is that there's some "lag" when scrolling the TableView. I'm loading images from the document folder, and I'm also resizing it to don't require too much processing, but it's still scrolling slowly. It's reusing cells (I checked the if(!cell)).
Here's my code:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
int row = indexPath.row;
if (row == 0) {
Cell01 *cell = nil;
cell = [tableView dequeueReusableCellWithIdentifier:#"Cell01ID"];
if (!cell) {
cell = (Cell01*)[[[NSBundle mainBundle] loadNibNamed:#"Cell01" owner:self options:nil] objectAtIndex:0];
cell.someLabel.text = #"First";
cell.someImage.image = [self imageInDocumentsDirectoryWithName:#"mainimage" andSize:CGSizeMake(200, 200)];
}
} else if (row % 2 == 0) {
Cell02 *cell = nil;
cell = [tableView dequeueReusableCellWithIdentifier:#"Cell02ID"];
if (!cell) {
cell = (Cell02 *)[[[NSBundle mainBundle] loadNibNamed:#"Cell02" owner:self options:nil] objectAtIndex:0];
cell.randomLabel.text = #"Second";
cell.someImage.image = [self imageInDocumentsDirectoryWithName:#"secondimage" andSize:CGSizeMake(200, 200)];
}
} else {
Cell03 *cell = nil;
cell = [tableView dequeueReusableCellWithIdentifier:#"Cell03ID"];
if (!cell) {
cell = (Cell03 *)[[[NSBundle mainBundle] loadNibNamed:#"Cell03" owner:self options:nil] objectAtIndex:0];
cell.anotherLabel.text = #"Third";
cell.someImage.image = [self imageInDocumentsDirectoryWithName:#"thirdimage" andSize:CGSizeMake(200, 200)];
}
}
}
- (UIImage *)imageInDocumentsDirectoryWithName:(NSString *)fileName andSize:(CGSize)size
{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString* path = [documentsDirectory stringByAppendingPathComponent:fileName];
UIImage *image = [UIImage imageWithContentsOfFile:path];
image = [image resizedImageToFitInSize:size scaleIfSmaller:YES];
return image;
}
Any idea how to improve this tableview (and make it scrolls faster)?
I think scrolling slowly is due to loading image on cell from document directory. fetching images from Doc dir takes some times and when ever u scroll ur table view, a new cell is created and image is loaded from doc dir which takes some time. try to use Lazy loading of image on cell. Also load images in a new thread not in main thread..
There is a sample project of Apple which helps u. lazy loading table view
I hope this will helps u .
Consider loading the images asynchronously. You could keep the references to all the UIImageView in a mutable array, start loading images in an asynchronous block, e.g. using GCD, and then update the image views as they get loaded.
Here's a rough example of how it could look (this assumes you have an ivar NSMutableArray *_imageViews, initialized with the correct size of elements, and filled with nils). I'm coding from the hip here, but I hope you get the idea. BTW, you can fill the mutable array with nils by inserting [NSNull null] into it.
I promise that if you implement this correctly, you'll see a marked improvement in the scrolling speed :)
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
int row = indexPath.row;
if (row == 0) {
Cell01 *cell = nil;
cell = [tableView dequeueReusableCellWithIdentifier:#"Cell01ID"];
if (!cell) {
cell = (Cell01*)[[[NSBundle mainBundle] loadNibNamed:#"Cell01" owner:self options:nil] objectAtIndex:0];
cell.someLabel.text = #"First";
[_imageViews replaceObjectAtIndex:row withObject:cell.someImage];
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(queue, ^{
UIImage *image = [self imageInDocumentsDirectoryWithName:#"thirdimage" andSize:CGSizeMake(200, 200)];
// because UI needs to be updated on the main thread,
// dispatch yet another block.
dispatch_async(dispatch_get_main_queue(), ^{
UIIMageView *imageView = [_imageViews objectAtIndex:row];
ImageView.image = image;
});
});
}
// et cetera
}
There are two potential performance issues with your current implementation. The first is using NSBundle instead of UINib to load the nib files. NSBundle reloads the nib file from the filesystem each time, whereas UINib reads a nib file once and caches its content in memory. Since it doesn't need to reread the nib from the filesystem each time, instantiating the objects should be orders of magnitude faster using UINib.
So instead of doing this...
cell = [[[NSBundle mainBundle] loadNibNamed:#"Cell02" owner:self options:nil] objectAtIndex:0];
...do this:
cell = [UINib loadNibNamed:#"Cell02" owner:self] objectAtIndex:0];
The second problem is similar; the current implementation is reloading the same images from the filesystem each time instead of caching them in memory and reusing them. To solve this, you could add an instance variable of type NSArray or NSDictionary (depending on how you prefer to retrieve the images), and then check before loading the image to see if it's already in the collection. If not, load the image and store it in the collection before using it. Otherwise, used the cached image instead of loading it again.
So instead of doing this...
cell.someImage.image = [self imageInDocumentsDirectoryWithName:#"thirdimage" andSize:CGSizeMake(200, 200)];
...do something like this:
// Note: Consider defining constants for the keys/filenames.
UIImage *image = [self.cachedImages objectForKey:#"thirdimage"];
if (image == nil) {
image = [self imageInDocumentsDirectoryWithName:#"thirdimage" andSize:CGSizeMake(200, 200)];
[self.cachedImages setObject:image forKey:#"thirdimage"];
}
cell.someImage.image = image;
If you need to cache a lot of images this way, consider using NSCache instead of NSDictionary to help keep the cache from growing too large.
I just finished implementing something similar, and if you make sure that all of the images in the documents directory are already the correct size (200 x 200) then this will work just fine without having to load asynchronously.
If you need the images to be larger, then generate thumbnails that are the correct size when you save the original file, as it actually is taking too much processing to resize the images in "real-time".
In this case though, you only have three images. If you simply cache the image after it has been resized and keep reusing it (instead of making new ones), then it will be even faster than that.

Image in tableviewcell slow down scrolling

My tableview consists of images loading from server, this slow down my tableview scrolling. Below is my code . any idea, please help me.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
CustomTblViewCellFacetoface *cell = (CustomTblViewCellFacetoface *) [tableView dequeueReusableCellWithIdentifier:#"cellA"];
if (cell == nil)
{
NSArray *topLevelObjects = [[NSBundle mainBundle] loadNibNamed:#"CustomTblViewCellFacetofaceNib" owner:Nil options:nil];
for (id currentObject in topLevelObjects)
{
if ([currentObject isKindOfClass:[UITableViewCell class]])
{
cell = (CustomTblViewCellFacetoface *) currentObject;
break;
}
}
}
// configure cell
IStructFacetofaceRequests *objappointmentdetails = [M_ArrFacetofaceRequests objectAtIndex:indexPath.row];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
cell.backgroundColor = [UIColor clearColor];
cell.m_CtrllblName.text = objappointmentdetails.m_strUsername;
cell.m_CtrllblVenue.text = [NSString stringWithFormat:#"Venue : %#",objappointmentdetails.m_strVenue];
cell.m_CtrllblDate.text = [NSString stringWithFormat:#"%# - %#",objappointmentdetails.m_strStartDate,objappointmentdetails.m_strEndDate];
[cell.m_CtrllblName setTextColor:[UIColor colorWithRed:(113/255.f) green:(113/255.f) blue:(113/255.f) alpha:1.0f]];
[cell.m_CtrllblVenue setTextColor:[UIColor colorWithRed:(113/255.f) green:(113/255.f) blue:(113/255.f) alpha:1.0f]];
[cell.m_CtrllblDate setTextColor:[UIColor colorWithRed:(113/255.f) green:(113/255.f) blue:(113/255.f) alpha:1.0f]];
cell.m_CtrllblName.font=[UIFont fontWithName:#"Arial-BoldMT" size:16];
NSData * imageData = [[NSData alloc] initWithContentsOfURL: [NSURL URLWithString: objappointmentdetails.m_strImageurl]];
cell.m_CtrlImgViewUser.image=[UIImage imageWithData: imageData];
[cell.m_CtrlBtnView addTarget:self action:#selector(MoveToNextView:) forControlEvents:UIControlEventTouchUpInside];
cell.m_CtrlBtnView.tag=indexPath.row;
return cell;
}
this is the code i used in cellfor row at index path.
You can solve that by using Asynchronous loading..
please go through this tutorial..
http://www.markj.net/iphone-asynchronous-table-image/
You can use UITableView lazy loading .
here an sample from apple
and u can see this project at github
Yes, UITableView is designed around the assumption of lazy loading. When you make a UITableView, you do not load any of the entries at all. Instead you wait for the system framework to call your cellForRowAtIndexPath method. That method gets called once for every cell that needs to be loaded, and that is just for the cells that are visible at the time. As the user scrolls the table view, new cells come into view, and your cellforRowAtIndexPath method gets called again for each new cell coming into view.
Now that is the general principle. But if your cells are being populated by data from a server, then there are some additional considerations. You could structure your cellForRowAtIndexPath to be as lazy as possible and call the server for each and every cell that comes into view. But the network delays would make the user experience really awful. So it is to your advantage to buffer up a number of cells worth of data ahead of time in a data structure other than the cells in a UITableView. That way, when cellForRowAtIndexPath gets called, you will be able to quickly supply the contents of the cell by constructing it from the buffered data. Exactly how much data to buffer depends on how large each data element is, and what else your application is doing in the way of memory allocation. Offhand, I see nothing wrong with buffering 500 to 1000 cells worth of data in your app. But don't mix up your buffering of the data with the UITableView's queuing and reusing of cells. There is no reason to maintain a large number of cells ready to go - just the data that goes into those cells.

How to improve performance while using UIWebView in cells of table view?

I am creating an application which uses a web service.And retrieves a list of users and there details like images, user id and there names.I displayed all the information related to users in table view, Thus each of the cell in the table view has an image with the for tables in it. I am using a Custom cell class to create the individual cells. selecting any row in table presents a detail view (using navigation) which show a larger image and all the details related to the particular user i selected.
in customcell and detail view class i am using web view to display image.
But when i run the app the images gets a bit of delay to display and same happens with the detail view.
Is there any alternative so that i can improve the performance of the table view so that i can have smooth scrolling of table view with out any delay in image loading and detail view??
here is the code...
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CustomCellIdentifier = #"CustomCellIdentifier ";
CustomCell *cell = (CustomCell *)[tableView
dequeueReusableCellWithIdentifier: CustomCellIdentifier];
if (cell == nil)
{
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"CustomCell" owner:self options:nil ];
//cell = [[CustomCell alloc] initwi ];
for (id oneObject in nib)
if ([oneObject isKindOfClass:[CustomCell class]])
cell = (CustomCell *)oneObject;
}
NSUInteger row = [indexPath row];
NSString *imageName = [imgArray objectAtIndex:row];
NSString *completeImageUrl = [[NSString alloc] initWithFormat:#"http://122.160.153.166:201/%#", imageName];
NSURL *url = [NSURL URLWithString:completeImageUrl];
//NSURLRequest *requestObj = [NSURLRequest requestWithURL:url];
NSData *imageData = [[NSData alloc] initWithContentsOfURL:url];
UIImage *image = [UIImage imageWithData:imageData]; /// check to see if we are getting all the arrays such as image array and userId array and name array of same size..
if(image == nil)
{
}
cell.imgView.image = image; /// other wise an execption of out out array range will be shown
[image release];
[imageName release];
//[cell.webView initWithFrame:CGRectZero];
//[cell.webView loadRequest:requestObj];
//cell.webView.frame = CGRectMake(20, 0, 80.0, 64);
cell.userIdLabel.text = (NSString *)[userId objectAtIndex:row];
cell.nameLabel.text = (NSString *)[userName objectAtIndex:row];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
return cell;
}`
i think problem can be in imgArray array as i am setting it from other class. Where i request the web service and fetched all the data about users .
Any help is greatly appreciated . Thanks in advance
I got the same problem. For that I used EGOImageCache and some thing.
Find this Url for EGOImage
Download files those names starts with "EGO", and add those to your project.
and write the following code where ever you want to put the image:
EGOImageView *imgView = [[EGOImageView alloc] initWithFrame:CGRectMake(50,50,220,360)];
NSString *imageName = [imgArray objectAtIndex:row];
NSString *completeImageUrl = [[NSString alloc] initWithFormat:#"http://122.160.153.166:201/%#", imageName];
NSURL *url = [NSURL URLWithString:completeImageUrl];
imgView.imageUrl = url;
[self.view addSubView:imgView];
Thats it. Use the similar code, where ever you want the image.
At the first time while loading it will take some time to download the image. But later it will cache the image and use it the next time.
Is there any alternative so that i can improve the performance of the table view so that i can have smooth scrolling of table view with out any delay in image loading
For this the answer is Lazy Loading of images in cells
You can implement lazy loading on webviewDidLoad which shows that webview has loaded completely
Using a UIWebView to display a single image is overkill. You should be using NSURLConnection (or one of many alternative HTTP wrappers/libraries) to load the image data and UIImageView to display it in each of your table cells. In my experience, there is no way (or at least no straightforward way) to eliminate the rendering delay when using UIWebView.
Why are you using the webview for displaying the images. Imageview should be used instead. If you are getting the images from the server then you should get those in separate thread and after you receive the images you should reload that particular row.
Some code snippet is like this:
- (UITableViewCell *)cellForRowAtIndexPath:(NSIndexPath *)indexPath
...
...
UIImage *img = (UIImage *)[imagesArray objectAtIndex:indexPath.row];
if(img == nil){
[imgView setImage:temporaryImage];
[NSThread detachNewThreadSelector:#selector(getTheThumnbails:) toTarget:self withObject:indexPath];
}
else
[imgView setImage:img];
for further assistance look at this
Hope this helps.
Thanks,
Madhup
okay finally i removed the uiweb view from my app and used Imaged view and succeed.
i used the link that was given by the developer of the tweetie . here it is link text
i used the ABTableViewCell class and created the whole cell using the code.
The scrolling was very jerky when i executed the app. after applying almost 4 hours and with the help of lazy loading i was able to run my app smoothly. I stored the data which is retrieved from url into an array then applied the concept in tableView:cellForRowAtIndexPath:
method..
Thanks you guys for helping me ...
Three20 has a rich-text table view cell class (TTStyledTextTableCell I think) - should render significantly faster than an embedded UIWebView. You could also roll your own, though that would take a lot longer.

release NSData in NSManagedObject

I use datamodel to store 2 objects : Video, Images.
Video contain just string attributes and Images have 2 "Binary data" attributes.
At the start the 2 binary data attributes was in the video object.
But all videos are loading during initialization of UITableView.
For 400 videos binary data represent 20 Mo, so imagine with 4000 videos...
Now with 2 objects the UITableView loading work well.
I load binary data when it's necessary in the method : tableView:cellForRowAtIndexPath
But now more I scroll into the list, more the memory grow up :(
look at my method :
- (UITableViewCell *)tableView:(UITableView *)myTableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"videoCell";
Video *theVideo = (Video *)[[self fetchedResultsController] objectAtIndexPath:indexPath];
VideoCellViewController *cell = (VideoCellViewController *)[myTableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
[[NSBundle mainBundle] loadNibNamed:#"VideoCellView" owner:self options:nil];
cell = editingTableViewCell;
self.editingTableViewCell = nil;
}
cell.video = theVideo;
return cell;
}
And the method setvideo in VideoCellViewController
- (void)setVideo:(Video *)newVideo {
if (newVideo != video) {
[video release];
video = [newVideo retain];
}
NSData *imageData = [video.allImages valueForKey:#"thumbnailImage"];
UIImage *uiImage = [[UIImage alloc] initWithData:imageData];
smallImage.image = uiImage;
nameLabel.text = video.displayName;
[uiImage release];
}
Even without set the smallImage, I have memory trouble.
If I load the image object, it's never release.
I try a lot of solution to release memory without succes...( didTurnIntoFault, release, CFRelease...)
In performance tool, I can see my binary data as CFData.
I use a lot iPhoneCoreDataRecipes and PhotoLocations sample.
I need help to clean my memory ;)
Thanks
Samuel
Clearly there is something going on with your table cell creation logic. Let's take a look at a typical cellForRow delegate handler first..
static NSString *MyIdentifier = #"MyIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:MyIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:MyIdentifier] autorelease];
}
// do stuff with cell
return cell;
Here we see we are
trying to get a reusable cell
if that fails (nil) create a new one and pass the reusable id to the ctor
then do stuff with the cell (new or existing) and return it
If you do not key the cell for reuse in the table view, you will always get a 'nil' cell returned from the dequeue, hence the need to create new cells every time. This will cause memory to continue to grow as you scroll around, but stay fairly flat when idle.
EDIT:
Assuming your cell is fine, then you need to narrow down if it's the video data or the image data that is leaking. What is smallImage? And are you sure you do not want to do everything only when the video is new?
- (void)setVideo:(Video *)newVideo {
if (newVideo != video) {
[video release];
video = [newVideo retain];
NSData *imageData = [video.allImages valueForKey:#"thumbnailImage"];
UIImage *uiImage = [[UIImage alloc] initWithData:imageData];
smallImage.image = uiImage;
nameLabel.text = video.displayName;
[uiImage release];
}
}