Objective C - UITableViewCell loading image asynchronously - objective-c

I am displaying a table. Each row has an image icon, loaded from an URL.
Since downloading images synchronously blocks the UI, I've implemented am asynchronous way via grand central dispatch.
My problem is that when I scroll down and up, since cells are being re-used, the incorrect images show up.
I can guess why this is happening - it's because the re-used cells update the image and therefore, previous cells will now have the newly downloaded, and wrong, image. What would be an ideal way to resolve this?
Here's my code.
For each image downloaded, I'm storing it in a singleton class called "ImageStore".
// set the data for each cell - reusing the cell
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"UITableViewCell"];
if (!cell) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle
reuseIdentifier:#"UITableViewCell"];
}
// setting the image for each cell
// first check if there is UIImage in the ImageStore already
NSString *imageUrl = [obj objectForKey:#"image"];
if (imageUrl) {
if ([[ImageStore sharedStore] imageForKey:imageUrl]) {
[[[tableView cellForRowAtIndexPath:indexPath] imageView] setImage:[[ImageStore sharedStore] imageForKey:imageUrl]];
} else {
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0ul);
dispatch_async(queue, ^{
UIImage *image = [UIImage imageWithData:[NSData dataWithContentsOfURL:
[NSURL URLWithString:[obj objectForKey:#"image"]]]];
dispatch_sync(dispatch_get_main_queue(), ^{
[[ImageStore sharedStore]setImage:image forKey:imageUrl];
[tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:indexPath]withRowAnimation:UITableViewRowAnimationNone];
[[[tableView cellForRowAtIndexPath:indexPath] imageView] setImage:image];
});
});
}
}
return cell;
}

Try this:
NSString *imageUrl = [obj objectForKey:#"image"];
if (imageUrl) {
if ([[ImageStore sharedStore] imageForKey:imageUrl]) {
[[cell imageView] setImage:[[ImageStore sharedStore] imageForKey:imageUrl]];
} else {
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0ul);
dispatch_async(queue, ^{
UIImage *image = [UIImage imageWithData:[NSData dataWithContentsOfURL:
[NSURL URLWithString:[obj objectForKey:#"image"]]]];
dispatch_sync(dispatch_get_main_queue(), ^{
[[cell imageView] setImage:image];
[cell setNeedsLayout];
});
});
}
EDIT : Check this grand-central-dispatch-for-ios-lazy-loading for tableview lazy loading

A little bit of modification from Prince Answer
NSString *imageUrl = [obj objectForKey:#"image"];
if (imageUrl)
{
if ([[ImageStore sharedStore] imageForKey:imageUrl])
{
//This condition means the current cell's image has been already downloaded and stored. So set the image to imageview
[[cell imageView] setImage:[[ImageStore sharedStore] imageForKey:imageUrl]];
}
else
{
//While reusing this imageView will have previous image that will be visible till the image is downloaded. So i am setting this image as nil.
[[cell imageView] setImage:nil];
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0ul);
dispatch_async(queue, ^{
//Called Immediately.
UIImage *image = [UIImage imageWithData:[NSData dataWithContentsOfURL:
[NSURL URLWithString:[obj objectForKey:#"image"]]]];
dispatch_sync(dispatch_get_main_queue(), ^{
//Called when the image is downloaded
//Store in any external object. So that next time reuse this will not be downloaded
[[ImageStore sharedStore]setImage:image forKey:imageUrl];
//Also set the image to the cell
[[cell imageView] setImage:image];
[cell setNeedsLayout];
});
});
}
}

Take a look at AFNetworking... They make dealing with network callbacks EASY!!! I recommend AFNetworking over ASIHTTPRequest because AFNetworking is keeping updated and ASIHTTPRequest is not... they kinda just stopped developing.
Here is an example of how to use AFNetworking to download images asynchronously:
NSDictionary * object = [self.array objectAtIndex:indexPath.row];
NSDictionary * image = [object valueForKey:#"image"];
NSString *imageUrl = [image valueForKeyPath:#"url"];
NSURL *url = [NSURL URLWithString:imageUrl];
[cell.imageView setImageWithURL:url placeholderImage:[UIImage imageNamed:#"empty-profile-150x150.png"]];
The setImageWithURL: placeholderImage: method is what I used to do this... Rather than multiple methods and lines of code, I accomplish everything with this line.
This entire line of code does exactly what you want to do. There is really no need to recreate the wheel :). It does help though going through the lower level of programming to really understand the implementation of what is REALLY going on under the hood.
View the link to download the library and view more examples on how to use it... Seriously, it makes your life alot easier not having to worry THAT MUCH about threads and GCD.
AFNetworking Demo
I haven't dived into the code of AFNetworking but my application runs like BUTTER when loading the images into the cells. It looks great :)
Oh and here the docs for AFNetworking: AFNetworking Documentation

I've noticed this behavior, too.
The only general solution I could find is to disable cell reuse.

Related

table view with images which are loaded from server in iphone

Hi I am developing IOS application. My application contains table view with image as part of my table. I am loading my image from server. It is working fine. But problem with my table view is once I scroll my table view it is start flickering my images. That mean it showing wrong image for some time after some time it shows right images. this behaviour continues when I scroll. Is there any need to explicitly call any object to nil or release some cell object or holding some cell objects. My cell for table view looks like :
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *simpleTableIdentifier = #"MediaContentCell";
MediaContentCell *cell = (MediaContentCell *)[tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell == nil) {
cell = (MediaContentCell *)[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:simpleTableIdentifier];
}
VideoDataModel *videoData = [_mediaContentArray objectAtIndex:indexPath.row];
cell.mediaTitle.text = videoData.title;
cell.mediaSubtitle.text = videoData.shortdescription;
NSMutableArray *posters = videoData.poster;
dispatch_queue_t myQueue = dispatch_queue_create("ImageQue",NULL);
dispatch_async(myQueue, ^
{
UIImage *image;
if(!posters)
{
image = [UIImage imageNamed:#"dummyprog_large1.png"];
}
else
{
for(int index = 0 ; index < posters.count; index++)
{
PosterDataModel *posterData = [posters objectAtIndex:index];
if([posterData.postertype isEqualToString:POSTER_TYPE_LANDSCAPE])
{
image = [[UIImage alloc] initWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:posterData.posterurl]]];
break;
}
}
}
dispatch_async(dispatch_get_main_queue(), ^
{
cell.mediaPicture.image = image;
});
});
[cell setSelectionStyle:UITableViewCellSelectionStyleNone];
return cell;
}
Is there any one can help me for this? Need some help Thank you.
use - SDWebImage
[cell.imageView sd_cancelCurrentImageLoad];
[cell.imageView setImageWithURL:[NSURL URLWithString:#"http://www.domain.com/path/to/image.jpg"]
placeholderImage:[UIImage imageNamed:#"placeholder.png"]];
I am using this framework and Its working fine for me.
cell.imageView.image = [UIImage imageWithData:yourDefaultImgUrl];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSData *imageData = [NSData dataWithContentsOfURL:yourServerImageUrl];
if (imageData){
dispatch_async(dispatch_get_main_queue(), ^{
UITableViewCell *updateCell = [tableView cellForRowAtIndexPath:indexPath];
if (updateCell)
updateCell.imageView.image = [UIImage imageWithData:imageData];
});
}
});
It helps you :)
It's the reuse mechanism that causes your problem
Say, if your table view has 1000 cells to display, and 5 cells are visible on the screen at a time, iOS will only create 6 UITableViewCell objects in the memory.
In your code, the image will be loaded asynchronously from the network, and then set to the [mediaPicture] belonging to the cell at an index path, but when you scroll the table view, because of the reuse mechanism, the [cell.mediaPicture] might not be correctly related to the index path anymore, and the downloaded image will be wrongly set.
You can take a look at this question about the reuse mechanism:
UITableViewCell - Understanding "reuseable"
And Amol's answer is exactly the solution for your case.

Data doesn't load in UITableView until I scroll

I am trying to load parsed data in cells, but the problem is that it is happening synchronously and UitableView doesn't show until the data has finished loading. I tried to solve the problem by using performSelectorInBackground, but now data isn't loaded in the cells until I start scrolling. Here is my code:
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
[self performSelectorInBackground:#selector(fethchData) withObject:nil];
}
- (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
self.listData = nil;
self.plot=nil;
}
-(void) fethchData
{
NSError *error = nil;
NSURL *url=[[NSURL alloc] initWithString:#"http://www.website.com/"];
NSString *strin=[[NSString alloc] initWithContentsOfURL:url encoding:NSUTF8StringEncoding error:nil];
HTMLParser *parser = [[HTMLParser alloc] initWithString:strin error:&error];
if (error) {
NSLog(#"Error: %#", error);
return;
}
listData =[[NSMutableArray alloc] init];
plot=[[NSMutableArray alloc] init];
HTMLNode *bodyNode = [parser body];
NSArray *contentNodes = [bodyNode findChildTags:#"p"];
for (HTMLNode *inputNode in contentNodes) {
[plot addObject:[[inputNode allContents] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]];
}
NSArray *divNodes = [bodyNode findChildTags:#"h2"];
for (HTMLNode *inputNode in divNodes) {
[listData addObject:[[inputNode allContents] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]];
}
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
//here you check for PreCreated cell.
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
}
//Fill the cells...
cell.textLabel.text = [listData objectAtIndex:indexPath.row];
cell.textLabel.font = [UIFont boldSystemFontOfSize:14];
cell.textLabel.numberOfLines=6;
cell.textLabel.textColor=[UIColor colorWithHue:0.7 saturation:1 brightness:0.4 alpha:1];
cell.detailTextLabel.text=[plot objectAtIndex:indexPath.row];
cell.detailTextLabel.font=[UIFont systemFontOfSize:11];
cell.detailTextLabel.numberOfLines=6;
return cell;
}
Put this somewhere after the data is loaded successfully:
dispatch_async(dispatch_get_main_queue(), ^{
[self.tableView reloadData];
});
This fix the problem of calling a GUI update while you're not in the main thread.
This code uses the GCD Technology from Apple to force the reload data function to run on main thread. Read more about
Concurrency Programming Guide for more understanding (it's quite large field so that it's hard to explain in the comment)
Anyway, it's not very recommended if you don't understand it well because it causes the program to crash some rare cases.
For swift 3:
DispatchQueue.main.async(execute: { () -> Void in
self.tableView.reloadData()
})
For swift 2:
dispatch_async(dispatch_get_main_queue(), { () -> Void in
self.tableView.reloadData()
})
All you really need to do is any time you have an update to your back-end data, call
[tableView reloadData];
Since this is happening synchronously, you should probably have a function like
-(void) updateTable
{
[tableView reloadData];
}
and after adding the data in your download call
[self performSelectorOnMainThread:#selector(updateTable) withObject:nil waitUntilDone:NO];
U can use [cell setNeedsDisplay];
for example:
dispatch_async(dispatch_get_main_queue(), ^{
[cell setNeedsDisplay];
[cell.contentView addSubview:yourView];
});
I had this problem and I was dealing with it all the day.
I am using static cells and reloadData is causing the wrong loading, it displays only the visible cells and remove the others.
What I noticed is that when I scrolled down (y in negative value) the cells where loaded correctly, so I wrote this code and it worked, even though I don't like to let it in this way.
Shoot if you find any better solution.
-(void)reloadTableView{
CGPoint point = self.tableSettings.tableView.contentOffset;
[self.tableSettings.tableView reloadData];
[UIView animateWithDuration:.001f animations:^{
[self.tableSettings.tableView setContentOffset:CGPointMake(point.x, -10)];
} completion:^(BOOL finished) {
[UIView animateWithDuration:.001f animations:^{
[self.tableSettings.tableView setContentOffset:point];
} completion:^(BOOL finished) {
}];
}];
}
I was having the exact same problem! I wanted the UITableView to be fully populated before the view controller appeared. Envil's post gave me the information I needed, but my solution ended up being different.
Here's what I did (remodeled to fit the context of the question asker).
- (void)viewDidLoad {
[super viewDidLoad];
[self performSelectorInBackground:#selector(fethchData) withObject:nil];
}
- (void)viewWillAppear {
[tableView reloadData];
}
First, this semi-solved my related problem. I want to round corners of an image in a table cell. Dispatching asynchronously fixed the problem for some but not all of the images. Any ideas?
Second, I think you are supposed to avoid creating a strong reference cycle by using a closure capture list like this:
DispatchQueue.main.async(execute: { [weak weakSelf = self] () -> Void in
weakSelf!.tableView.reloadData()
})
See: https://developer.apple.com/library/prerelease/content/documentation/Swift/Conceptual/Swift_Programming_Language/AutomaticReferenceCounting.html#//apple_ref/doc/uid/TP40014097-CH20-ID52
I experienced the same issue when using self-sizing cells, and I found that setting the estimatedHeight to 50 would fix the problem.
Set estimatedHeight on the tableView itself or return an estimate from estimatedHeightForRowAt in your UITableViewDelegate.
It seems to work as long as the estimate is more than 0.

GCD UITableView asynchronous load images, wrong cells are loaded until new image download

I have a UITableView with custom cells. I load images asynchronously using Grand Central Dispatch. Everything works fine, but when I scroll down, previously loaded images are shown till the new image is downloaded. Here is my code:
if (![[NSFileManager defaultManager] fileExistsAtPath:[path stringByAppendingPathComponent:#"image.png"]])
{
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0ul);
dispatch_async(queue, ^{
NSString *url=[pat stringByAppendingPathComponent:#"comments.txt"];
NSString *u=[NSString stringWithContentsOfFile:url encoding:NSUTF8StringEncoding error:nil];
NSURL *imageURL=[NSURL URLWithString:u];
NSData *image=[NSData dataWithContentsOfURL:imageURL];
[image writeToFile:[pat stringByAppendingPathComponent:#"image.png"] atomically:YES];
dispatch_sync(dispatch_get_main_queue(), ^{
cell.imageView.image=[UIImage imageWithContentsOfFile:[pat stringByAppendingPathComponent:#"image.png"]];
[cell setNeedsLayout];
NSLog(#"Download");
});
});
}
else
{
NSLog(#"cache");
cell.imageView.image=[UIImage imageWithContentsOfFile:[pat stringByAppendingPathComponent:#"image.png"]];
}
Any suggestions appreciated.
P.S. I reuse the cells
Rather than capturing the cell you need to capture the index path, then get the cell back using:
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
That way, if the cell is now off screen you'll get nil back and the image won't be set on the wrong cell.
The other thing you need to add after your dispatch_async() is a cell.imageView.image=somePlaceholderImage.
E.g.:
if (![[NSFileManager defaultManager] fileExistsAtPath:[path stringByAppendingPathComponent:#"image.png"]])
{
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0ul);
dispatch_async(queue, ^{
NSString *url=[pat stringByAppendingPathComponent:#"comments.txt"];
NSString *u=[NSString stringWithContentsOfFile:url encoding:NSUTF8StringEncoding error:nil];
NSURL *imageURL=[NSURL URLWithString:u];
NSData *image=[NSData dataWithContentsOfURL:imageURL];
[image writeToFile:[pat stringByAppendingPathComponent:#"image.png"] atomically:YES];
dispatch_sync(dispatch_get_main_queue(), ^{
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
cell.imageView.image=[UIImage imageWithContentsOfFile:[pat stringByAppendingPathComponent:#"image.png"]];
[cell setNeedsLayout];
NSLog(#"Download");
});
});
cell.imageView.image=[UIImage imageNamed:#"placeholder"];
}
else
{
NSLog(#"cache");
cell.imageView.image=[UIImage imageWithContentsOfFile:[pat stringByAppendingPathComponent:#"image.png"]];
}
In your - (void)tableView:(UITableView *)aTableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath { You need to clear out the image, or reset it to your spinner. Since table view rows are reused, this is the behavior you will see.
Doesn't UITableViewCell define -(void) prepareForReuse for that purpose?
Override it and clear your imageView in there.

dequeueReusableCellWithIdentifier causing problem on UIImageView

I am loading a tableView with 500 rows. The problem is that in each row there is a different picture. Or when I use dequeueReusableCellWithIdentifier, those picture are just loaded again and the real pictures I am looking for are not shown (I just have about 8 different pictures : the first 8 loaded on my screen). If I don't use the dequeureReusableCellIdentifier, all the picture are loaded. But will it slow the displaying ?
Here is the code (I am currently working on getting the picture cached) :
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CustomCellIdentifier = #"CustomCellIdentifier";
UITableViewCell *cell = [tableView
dequeueReusableCellWithIdentifier: CustomCellIdentifier];
NSLog(#"Launching CellForRowAtIndexPath");
if (cell == nil) {
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"CustomCell"
owner:self options:nil];
if ([nib count] > 0) {
cell = self.profilCell;
} else {
NSLog(#"failed to load CustomCell nib file!");
}
}
NSUInteger row = [indexPath row];
NSDictionary *rowData = [listProfils objectAtIndex:row];
UILabel *nameLabel = (UILabel *)[cell viewWithTag:nameValueTag];
nameLabel.text = [rowData objectForKey:#"name"];
NSString *finalId = [NSString stringWithFormat:#"http://graph.facebook.com/%#/picture", [rowData objectForKey:#"id"]];
UIImage *image = [[UIImage alloc] initWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:finalId]]];
[profilPic setImage:image];
return cell;
}
THank you ! :)
It looks like you have an ivar profilPic that is probably an outlet that gets linked when you load a new cell nib. If that's the case, it's always going to point to the last cell that you loaded and won't change the image in the cell you've just dequeued. Instead of using an outlet, you might want to identify that custom view some other way, like a tag. So, if you set the profile pic UIImageView's tag to 100, for example, in Interface Builder, you could do something like this:
UIImage *image = [[UIImage alloc] initWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:finalId]]];
UIImageView* cellImageView = (UIImageView*)[cell viewWithTag:100];
[cellImageView setImage:image];
Also, I just want to point out that -dataWithContentsOfURL: will load the URL synchronously on the main thread. If you're testing in the simulator on a fast connection, this will work pretty well. If, however, you are on 3G in SoHo on Friday afternoon... your app will probably start being killed by the watchdog.
I just met this problem, my solution is hold a private NSMutableDictionary to store the new images which asynchronously loaded from web before, use my identifier as key, UIImageView as Object (because I need to load the icon image first), when web image is ready, change it, When tableView dequeue return's null, I can read the original UIImage from my own cache.
Something like this.
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier];
if (!cell) {
UIImageView *imageView = [thumbnailCache objectForKey:identifier];
if (!imageView) {
cell.imageView.image = [UIImage imageNamed:#"icon.png"];
[thumbnailCache setObject:cell.imageView forKey:identifier];
} else {
cell.imageView.image = imageView.image;
}
}
When I load the actual image from web, refresh the thumbnail cache.
asynchronously_load_image_from_web(^(UIImage *image) {
cell.imageView.image = image;
[thumbnailCache setObject:cell.imageView forKey:identifier];
});

Accurate progress displayed with UIProgressView for ASIHTTPRequest in an ASINetworkQueue

Summary: I want to track the progress of file downloads with progress bars inside cells of a tableview.
I'm using ASIHTTPRequest in an ASINetworkQueue to handle the downloads.
It works, but the progress bars stay at 0%, and jump directly at 100% at the end of each download.
Details:
I set up my ASIHTTPRequest requests and ASINetworkQueue this way:
[Only an extract of my code]
- (void) startDownloadOfFiles:(NSArray *) filesArray {
for (FileToDownload *aFile in filesArray) {
ASIHTTPRequest *downloadAFileRequest = [ASIHTTPRequest requestWithURL:aFile.url];
UIProgressView *theProgressView = [[UIProgressView alloc] initWithFrame:CGRectMake(20.0f, 34.0f, 280.0f, 9.0f)];
[downloadAFileRequest setDownloadProgressDelegate:theProgressView];
[downloadAFileRequest setUserInfo:
[NSDictionary dictionaryWithObjectsAndKeys:aFile.fileName, #"fileName",
theProgressView, #"progressView", nil]];
[theProgressView release];
[downloadAFileRequest setDelegate:self];
[downloadAFileRequest setDidFinishSelector:#selector(requestForDownloadOfFileFinished:)];
[downloadAFileRequest setDidFailSelector:#selector(requestForDownloadOfFileFailed:)];
[downloadAFileRequest setShowAccurateProgress:YES];
if (! [self filesToDownloadQueue]) {
// Setting up the queue if needed
[self setFilesToDownloadQueue:[[[ASINetworkQueue alloc] init] autorelease]];
[self filesToDownloadQueue].delegate = self;
[[self filesToDownloadQueue] setMaxConcurrentOperationCount:2];
[[self filesToDownloadQueue] setShouldCancelAllRequestsOnFailure:NO];
[[self filesToDownloadQueue] setShowAccurateProgress:YES];
}
[[self filesToDownloadQueue] addOperation:downloadAFileRequest];
}
[[self filesToDownloadQueue] go];
}
Then, in a UITableViewController, I create cells, and add the name of the file and the UIProgressView using the objects stored in the userInfo dictionary of the request.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"fileDownloadCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
[[NSBundle mainBundle] loadNibNamed:#"FileDownloadTableViewCell" owner:self options:nil];
cell = downloadFileCell;
self.downloadFileCell = nil;
}
NSDictionary *userInfo = [self.fileBeingDownloadedUserInfos objectAtIndex:indexPath.row];
[(UILabel *)[cell viewWithTag:11] setText:[NSString stringWithFormat:#"%d: %#", indexPath.row, [userInfo valueForKey:#"fileName"]]];
// Here, I'm removing the previous progress view, and adding it to the cell
[[cell viewWithTag:12] removeFromSuperview];
UIProgressView *theProgressView = [userInfo valueForKey:#"progressView"];
if (theProgressView) {
theProgressView.tag = 12;
[cell.contentView addSubview:theProgressView];
}
return cell;
}
The progress bar are all added, with the progress set to 0%.
Then, at end of download, they instantly jump to 100%.
Some of the download are very big (more than 40Mb).
I do not do anything tricky with threads.
Reading the forums of the ASIHTTPRequest, it seems I'm not alone, but I couldn't find a solution.
Am I missing something obvious? Is this a bug in ASI* ?
ASIHTTPRequest can only report progress if the server is sending Content-Length: headers, as otherwise it doesn't know how big the response will be. (ASINetworkQueue also sends HEAD requests at the start to try to figure out document sizes.)
Try collecting all the network traffic with charlesproxy or wireshark, see if these headers are present and/or what is happening with the HEAD requests.