Showing Accurate Progress In UIProgressView While Downloading Images in iphone - iphone

I have four urls which consists images...
I'm downloding those images and placing them into documents folder..
here is my code..
-(void)viewDidLoad
{
NSMutableArray *myUrlsArray=[[NSMutableArray alloc]init];
[myUrlsArray addObject:#"http://blogs.sfweekly.com/thesnitch/steve_jobs3.jpg"];
[myUrlsArray addObject:#"http://www.droid-life.com/wp-content/uploads/2012/12/Steve-Jobs-Apple.jpg"];
[myUrlsArray addObject:#"http://2.bp.blogspot.com/-T6nbl0rQoME/To0X5FccuCI/AAAAAAAAEZQ/ipUU7JfEzTs/s1600/steve-jobs-in-time-magazine-front-cover.png"];
[myUrlsArray addObject:#"http://images.businessweek.com/ss/08/09/0929_most_influential/image/steve_jobs.jpg"];
[myUrlsArray addObject:#"http://cdn.ndtv.com/tech/gadget/image/steve-jobs-face.jpg"];
for (int i=0; i<myUrlsArray.count; i++)
{
[self downloadImageFromURL:[myUrlsArray objectAtIndex:i] withName:[NSString stringWithFormat:#"MyImage%i.jpeg",i]];
}
}
#pragma mark- downloading File
-(void)downloadImageFromURL:(NSString *)myURLString withName:(NSString *)fileName
{
UIImage *image = [[UIImage alloc] initWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:myURLString]]];
NSLog(#"%f,%f",image.size.width,image.size.height);
// Let's save the file into Document folder.**
NSString *documentsPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask, YES) objectAtIndex:0];
NSString *jpegPath = [NSString stringWithFormat:#"%#/%#",documentsPath,fileName];// this path if you want save reference path in sqlite
NSData *data2 = [NSData dataWithData:UIImageJPEGRepresentation(image, 1.0f)];//1.0f = 100% quality
[data2 writeToFile:jpegPath atomically:YES];
}
NOW... I need to display a UIProgressView for above downloading progress accurately.
how can i achieve this functionality...
Can any one provide some guidelines to achieve this..
Thanks in advance...

I'd suggest you use some asynchronous downloading technique (either AFNetworking, SDWebImage, or roll your own with delegate-based NSURLSession) rather than dataWithContentsOfURL so that (a) you don't block the main queue; and (b) you can get progress updates as the downloads proceed.
I'd also suggest creating a NSProgress for each download. When your delegate method gets updates about how many bytes have been downloaded, update the NSProgress object.
You then can associate each NSProgress with a observedProgress for a UIProgressView, and when you update your NSProgress, the UI can be updated automatically.
Or, if you and a single UIProgressView to show the aggregate progress of all of the NSProgress for each download, you can create a parent NSProgress, establish each download's NSProgress as a child of the parent NSProgress, and then, as each download updates its respective NSProgress, this will automatically trigger the calculation of the parent NSProgress. And again, you can tie that parent NSProgress to a master UIProgressView, and you'll automatically update the UI with the total progress, just by having each download update its individual NSProgress.
There is a trick, though, insofar as some web services will not inform you of the number of bytes to be expected. They'll report an "expected number of bytes" of NSURLResponseUnknownLength, i.e. -1! (There are logical reasons why it does that which are probably beyond the scope of this question.) That obviously makes it hard to calculate what percentage has been downloaded.
In that case, there are a few approaches:
You can throw up your hands and just use an indeterminate progress indicator;
You can try changing the request such that web service will report meaningful "expected number of bytes" values (e.g. https://stackoverflow.com/a/22352294/1271826); or
You can use an "estimated download size" to estimate the percentage completion. For example, if you know your images are, on average, 100kb each, you can do something like the following to update the NSProgress associated with a particular download:
if (totalBytesExpectedToWrite >= totalBytesWritten) {
self.progress.totalUnitCount = totalBytesExpectedToWrite;
} else {
if (totalBytesWritten <= 0) {
self.progress.totalUnitCount = kDefaultImageSize;
} else {
double written = (double)totalBytesWritten;
double percent = tanh(written / (double)kDefaultImageSize);
self.progress.totalUnitCount = written / percent;
}
}
self.progress.completedUnitCount = totalBytesWritten;
This is a bit of sleight of hand that uses the tanh function to return a "percent complete" value that smoothly and asymptotically approaches 100%, using the kDefaultImageSize as the basis for the estimation.
It's not perfect, but it yields a pretty decent proxy for percent completion.

Your call to dataWithContentsOfURL is synchronous, meaning you don't get updates as the download is in process.
You can use a library like AFNetworking (https://github.com/AFNetworking/AFNetworking) which has callbacks to the progress of the download.

Actually a better solution is to use SDWebImage manager which will load the images in the background for you and cache them. Then the next time you use that image it will check the cache. Google it.
That way the user also doesn't have to sit around and wait while you're downloading stuff..
Then look at this other question that has some ideas on how to do a status:
How to show an activity indicator in SDWebImage

Do not use dataWithContentsOfURL, you are blocking the main thread until the data arrives.
Instead create your own connection with NSURLConnection and start listening to your delegate.
connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response: get the total data size with [response expectedContentLength].
connection:(NSURLConnection *)connection didReceiveData:(NSData *)data: This is where you do your calculations and update your UIProgressView. Something like, loadedBytes/total data size.
Good luck.

Related

How to make UIProgressView to show progress of NSArray loading from file (iPhone)?

I hope it's even possible.
I've got code to load really big file (dictionary) after app started:
- (void)applicationDidFinishLaunching:(UIApplication *)application {
NSString *filePath = [NSString stringWithContentsOfFile:[[NSBundle mainBundle]
pathForResource:#"en_US" ofType:#"txt"]
encoding:NSUTF8StringEncoding error:nil];
dictionary = [NSSet setWithArray:[NSArray arrayWithArray:
[filePath componentsSeparatedByCharactersInSet:
[NSCharacterSet whitespaceAndNewlineCharacterSet]]]];
}
Also I've got proper code in viewDidLoad:
- (void)viewDidLoad {
[super viewDidLoad];
self.progressView.progress = 0.0;
[self performSelectorOnMainThread:
#selector(applicationDidFinishLaunching:)
withObject:nil
waitUntilDone:NO];
}
But I've got not a clue how to force UIProgressView to show progress of creating NSSet dictionary from an NSArray. It takes few seconds in iOS Simulator, so on device it can take over a dozen. I really need to show progress, and I prefer this way than Activity Indicator View.
I'm interested in how to get count of imported items at the moment (count of all items is known).
Any idea? :)
You need to use NSURLRequest/NSURLConnection to start an asynchronous request to get the dictionary data. The delegates of NSURLConnection will give you the bytes read and bytes remaining where you can perform a async dispatch to the main thread to update your progress view value.
If you have a long text file to parse, the framework classes will take long time. You can't change that. And you can't change that they will never call back during work to tell you about their progress.
Your only chance is to perform text file splitting on your own and set your progress as you dig yourself through your textfile. You can split a textfile with regular expressions. The "\w+" collect words with at least one character.
If you set the progress bar in a heavy working method you have to give it some time to refresh the screen once in a while. See the "futuredate magic" below.
Maybe the following can act as a starting point - in the code below the content of the text file is stored in the NSString "content".
NSError *error = NULL;
NSRegularExpression *regex = [NSRegularExpression
regularExpressionWithPattern:#"\\w+"
options:NSRegularExpressionCaseInsensitive
error:&error];
[regex enumerateMatchesInString:content
options:0
range:NSMakeRange(0, [content length])
usingBlock:^(NSTextCheckingResult *match, NSMatchingFlags flags, BOOL *stop){
// push one match to the dictionary
[dictionary addObject:[content substringWithRange:match.range]];
// update the progress bar
NSDate* futureDate = [NSDate dateWithTimeInterval:0.001 sinceDate:[NSDate date]];
[[NSRunLoop currentRunLoop] runUntilDate:futureDate];
self.progressbar.progress = (float) match.range.location/content.length;
}];
Note that the code is not optimized for speed. For example you should not update the progress bar with every token. Depending on how much tokens you have - count the detected ones and update the pgogress bar every 100 matches, or so...
Use SVProgressHUD. It has delegates such as showProgress to show progress.
EDIT:
Note that this is just a suggestion to the approach and not practical implementation. Depending on your observation you may or may not choose to implement it.
If it's a local file, you can take some calculated guess about the total time it takes to read the entire file. Then divide this time by 100.
Create an async queue to read from file using one of arrayWithContentsOfFile or dictionaryWithContentsOfFile or whatever. Implement a timer on main thread, and increment progress by 1 through it, and keep posting progress on main thread (do not read progress from async thread because it is never going to tell you of that, we are faking it).
Once arrayWithContentsOfFile returns, post 100% on main thread. You may need to tweak a bit to be accurate (like in Windows where you keep seeing file download time fluctuating) but variation will not be much I suppose. Every type of target device would have given hardware and memory so it would be simply a function of file size.

UIImageView performance within UITableViewCell using ASIHTTPRequest

This problem has been vexing me for a little over a day. The gist is that I have a Grouped UITableView setup such that there is only one entry per section. Each cell within the table view contains a UIImageView that takes up the entire width and length of the cell. Furthermore, each cell is at a specified set height and width.
Here is my init method:
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
[[self layer] setMasksToBounds:NO];
[[self layer] setShouldRasterize:YES];
[[self layer] setRasterizationScale:[[UIScreen mainScreen] scale]];
[[self layer] setCornerRadius:10];
_bgCoverView = [[UIImageView alloc] initWithFrame:CGRectZero];
[_bgCoverView setClipsToBounds:YES];
[[_bgCoverView layer] setCornerRadius:10];
[_bgCoverView setContentMode:UIViewContentModeScaleAspectFill];
[self.contentView addSubview:_bgCoverView];
[_bgCoverView release];
//Init other parts of the cell, but they're not pertinent to the question
}
return self;
}
This is my layout subviews:
- (void)layoutSubviews{
[super layoutSubviews];
if (!self.editing){
[_bgCoverView setFrame:CGRectMake(0, 0, tableViewCellWidth, self.contentView.frame.size.height)];
}
}
This is my setter for the cell:
- (void)setGroup:(Group*)group{
//Set background cover for the contentView
NSSet *usableCovers = [[group memories] filteredSetUsingPredicate:[NSPredicate predicateWithFormat:#"pictureMedData != nil || pictureFullData != nil || (pictureMedUrl != nil && NOT pictureMedUrl contains[cd] '/missing.png')"]];
Memory *mem = [usableCovers anyObject];
[_bgCoverView setImage:[UIImage imageWithContentsOfFile:#"no_pics_yet.png"]];
if (mem != nil){
[Folio cacheImageAtStringURL:[mem pictureMedUrl] forManagedObject:mem withDataKey:#"pictureMedData" inDisplay:_bgCoverView];
}
}
This is where I think I'm getting a performance ding. First, there's the filtered set call. If there are a lot of objects in the set, this could slow stuff down. However, there tend to be relatively few objects. Furthermore, when I removed this line of code, I saw no performance change, so it's pretty unlikely.
So, that pretty much leaves my cache method (which is located in a helper class). Here's the method:
+(void)cacheImageAtStringURL:(NSString *)urlString forManagedObject:(NSManagedObject*)managedObject withDataKey:(NSString*)dataKey inDisplay:(NSObject *)obj{
int objType = 0; //Assume UIButton
if (obj == nil)
objType = -1;
else if ([obj isKindOfClass:[UIImageView class]])
objType = 1; //Assign to UIImageView
NSData *data = (NSData*)[managedObject valueForKey:dataKey];
if ([data bytes]){
if (objType == 0) [(UIButton*)obj setBackgroundImage:[UIImage imageWithData:data] forState:UIControlStateNormal];
else if (objType == 1) [(UIImageView*)obj setImage:[UIImage imageWithData:data]];
return;
}
//Otherwise, do an ASIHTTPRequest and set the image when it's returned, save the data into core data so that we get a cache hit the next time.
}
Regardless of if the images are cached or not, there are major performance issues with scrolling down on this view. If I comment out the cache method, it works pretty well. Additionally, other views that call this method are sluggish, so I'm pretty sure it's something here.
I will also say, however, that I'm also suspicious of the cornerRadius code, however, I heard that if you set shouldRasterize to YES, it'll result in a performance speed-up. Still, I'm not sure if that's 100% true or if my implementation is off.
Any help would be greatly appreciated.
UPDATE
Still not 100% fixed yet, but we are getting there.
These variables must be set on the request:
[request setCachePolicy:ASIOnlyLoadIfNotCachedCachePolicy];
[request setCacheStoragePolicy:ASICachePermanentlyCacheStoragePolicy];
The first tells the cache to only ping the server for images if they are not cached. The second tells the cache to store the images permanently for the lifecycle of the app.
This got me part-way there. Some images loaded instantly whereas others seemed sluggish. I did more research and added these lines of code in my app delegate:
[[ASIDownloadCache sharedCache] setShouldRespectCacheControlHeaders:NO];
[ASIHTTPRequest setDefaultCache:[ASIDownloadCache sharedCache]];
The first line is crucial. ASIHTTPRequest's default action is to follow what the web server tells you. So, if it tells you in its headers not to cache a response, it won't. This line overrides that. Now, this worked really well on my iOS simulator. Then, I tried it on my 4S and it was slow again.
The reason was because I set up a block of code in my request that, upon the successful retrieval of an image, I would save it to Core Data. This call was being triggered every time, even for cached requests.
This is because ASIHTTPRequest will still make a request regardless of whether or not it uses a cached copy of your data. If it has a cached copy, it won't send out a request to a server, but will populate its request object's response data with cached data instead. So after my block takes care of display work, I call:
if ([request didUseCachedResponse]) return;
This works very well on the 4S and the 4. However, the 3GS is still disastrously slow :-(.
This is because ASIHTTPRequest is using a cached copy of my NSData and not my UIImage. So, it needs to re-create the image each time it uses the cache. This makes sense because ASIHTTPRequest is only returning data, and doesn't know what you are going to do with the data afterwards, so it'll always call your code that's set up when the request is returned. And because my code block converts the image from data, that's what I get.
A WAY FORWARD
I think to get the performance speedup I want, it's necessary to implement a custom UIImage cache. If we find the file in the cache, we return the UIImage object. If not, then we create a request and save it in the cache on return.
The tip with shouldRasterize is a valid one, though from my experience this decreases the quality of the graphic significantly. Also, since like iOS4.3 or so (can't remember anymore) they enormously improved the cornerRadius call, it's a very long time since I last needed to activate rasterizing for this kind of problem.
You could always deactivate cornerRadius and see how it performs.
What I really want to tell you however is that ASIHTTPRequest has built-in cache support, see
http://allseeing-i.com/ASIHTTPRequest/How-to-use#using_a_download_cache
Try it, it worked flawlessly for me. Think about what cache policies fit your needs best. Of course, if you need the images in CoreData you'll have to insert them, but I wouldn't try to cache them manually from CoreData.
Oh and something else ... ASIHTTPRequest is not under development anymore, you might want to consider switching to another framework (like AFNetworking). ASIHTTPRequest e.g. doesn't support ARC.
Check out this post. I use a blocks and GCD for image loading (especially useful in a TableViewCell). This loads the images on the fly if you put the method call in the cellForRowAtIndexPath method. I have no slugglish UI.

NSData & malloc In NSTimer, using a lot of memory in timer

I'm quite new to iPhone development. My target is a remote control app, the server of which is TightVNC. But I met a problem and it's driving me crazy... I've successfully connected to the server(using socket), and next would like to request desktop update at least every one second. So here comes the timer which is created through the selector in "performSelectorInBackground". The timer's main task is as fellow:
int picLength;
[self readExact:(char*)(&picLength) bySize:sizeof(int)];
char *picBuffer;
picBuffer = (char *)malloc(picLength);
[self readExact:picBuffer bySize:picLength];
NSData *picData = [[NSData alloc]initWithBytes:picBuffer length:picLength];
[self performSelectorOnMainThread:#selector(setPicInMainThread:) withObject:picData waitUntilDone:YES];
[picData release];
free(picBuffer);
And "setPicInMainThread" is as follow (each picture is around 200KB, iTouch is connected to PC through computer-to-computer wifi, so the speed would be fast enough):
- (void) setPicInMainThread:(NSData *)data {
[chatController.imageView.image release];
chatController.imageView.image = [UIImage imageWithData:data];
}
The app crushes after presenting the first desktop update. I am wondering if I've met the "memory leak" concerning NSTimer and NSData, which lots of people is talking about... If so, is there any way to solve the problem? Thank you very much for helping!
Your malloc code is looking bad. Why would you take the address of an int and then cast it as a character pointer? Then why would even pass an int for the size to the same function you pass a char * to get set? I have a feeling you are getting an EXC_BAD_ACCESS and it is because of your first few lines and the readExact method. Make sure you get the length the correct and pass the correct parameters.
int picLength;
[self readExact:(char*)(&picLength) bySize:sizeof(int)];
char *picBuffer;
picBuffer = (char *)malloc(picLength);

Why is saving these images to core data taking 17 sec + on the iPhone?

I have been working with Apple's iPhone CoreDateRecipes sample code to learn more about tableviews and core data. I have coded my own test app based off of that sample, and it works well except for one thing. When I choose a photo for the 'recipe', no matter if it is from the camera or the library, when I hit "Done" to leave editing mode, it takes about 15 seconds before returning control to the user. This happens when testing on the device - in simulator, there is still a delay, but it is only 2-4 seconds.
I tested the "edit/done" button without choosing a photo and editing other data, and it saves instantaneously, so I'm pretty sure the image is to blame. Below is the code where it leaves editing mode, and the image processing code - what can I add/change/remove to speed this up? I know these sample code pieces are just proofs of concept, but I can't believe they published an example with such a crappy user experience!
Thanks, as always, for any guidance...let me know if there is any other code you need to see, or you can see the whole sample project here
- (void)setEditing:(BOOL)editing animated:(BOOL)animated {
[super setEditing:editing animated:animated];
[self updatePhotoButton];
nameTextField.enabled = editing;
overviewTextField.enabled = editing;
[self.navigationItem setHidesBackButton:editing animated:YES];
if (!editing) {
NSManagedObjectContext *context = recipe.managedObjectContext;
NSError *error = nil;
if (![context save:&error]) {
NSLog(#"Error in RecipeDetailViewController:setEditing -- %#, %#",error, [error userInfo]);
abort();
}
}
}
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingImage:(UIImage *)selectedImage editingInfo:(NSDictionary *)editingInfo {
NSManagedObject *oldImage = recipe.image;
if (oldImage != nil) {
[recipe.managedObjectContext deleteObject:oldImage];
}
NSManagedObject *image = [NSEntityDescription insertNewObjectForEntityForName:#"Image" inManagedObjectContext:recipe.managedObjectContext];
recipe.image = image;
[image setValue:selectedImage forKey:#"image"];
CGSize size = selectedImage.size;
CGFloat ratio = 0;
if (size.width > size.height) {
ratio = 70.0 / size.width;
} else {
ratio = 70.0 / size.height;
}
CGRect rect = CGRectMake(0.0, 0.0, ratio * size.width, ratio * size.height);
UIGraphicsBeginImageContext(rect.size);
[selectedImage drawInRect:rect];
recipe.thumbnailImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
[self dismissModalViewControllerAnimated:YES];
}
First, as Gilbert pointed out, example code is not meant for production use and will be slow.
Second, you should not store images in Core Data.  The example may show how to do it but it is generally a very bad idea.  You should be storing images on disk and then keeping a pointer (file path) to the image in Core Data.  There are some exceptions to this rule (very small images) but you should rethink your design.
Lastly, A lot of the slowness you are seeing may not be Core Data related.  The image picker code is very slow on its own.  I would recommend changing the code to just write to disk and see how slow that is compared to the writing to Core Data.  I would be surprised if it was much faster.
Update
You can store small images inside of Core Data and my advice from other posts stands, mores for the desktop than iOS.  The reason for this is the cache.  On iOS, the cache that Core Data uses is very small.  If you store images in the database that are large, you can blow out that cache easily and cause future calls that should be in the cache to hit the disk instead.  This is not a hard and fast rule of "don't store binary data" but more of a rule of watch your performance and if you are hitting the disk more than you should, binary data could easily be the cause.
Contacts
With regard to contacts, you can be slower because they are doing things differently than you are and they could easily be using private APIs to access the camera.  Because it is Apple, they don't necessarily play by the same rules as us.
I'm not an iPhone developer, but generally, example code does not take into account the user experience. Example code shows examples.
In general, you need to perform expensive (long running) operations in additional threads.
Maybe this blog post will help: Respect the Main Thread
I downloaded the project, built it and ran it in the simulator. I couldn't reproduce your problem. I found that the time it took to save an image was visually instantaneous i.e. no longer than the view transition.
If you see the same issue on the original, unmodified project, then you have something else going on. Make sure you have the latest version of the project which should be the one at your link. I know there is at least one really old one floating around because I hit it recently.

concurrent background downloads on iphone

I am trying to create class that will handle multiple downloads at same time (I need to download a lot of small files) and I have problems with "disappearing" connections.
I have function addDonwload that adds url to list of urls to download, and checks if there is free download slot available. If there is one it starts download immediately. When one of downloads finishes, I pick first url form list and start new download.
I use NSURLConnection for downloading, here is some code
- (bool) TryDownload:(downloadInfo*)info
{
int index;
#synchronized(_asyncConnection)
{
index = [_asyncConnection indexOfObject:nullObject];
if(index != NSNotFound)
{
NSLog(#"downloading %# at index %i", info.url, index);
activeInfo[index] = info;
NSURLRequest *request = [NSURLRequest requestWithURL:info.url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:15];
[_asyncConnection replaceObjectAtIndex:index withObject:[[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:TRUE]];
//[[_asyncConnection objectAtIndex:i] scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
return true;
}
}
return false;
}
- (void)connectionDidFinishLoading:(NSURLConnection*)connection
{
[self performSelectorOnMainThread:#selector(DownloadFinished:) withObject:connection waitUntilDone:false];
}
- (void)DownloadFinished:(id)connection
{
NSInteger index = NSNotFound;
#synchronized(_asyncConnection)
{
index = [_asyncConnection indexOfObject:(NSURLConnection*)connection];
}
[(id)activeInfo[index].delegate performSelectorInBackground:#selector(backgroundDownloadSucceededWithData:) withObject:_data[index]];
[_data[index] release];
[activeInfo[index].delegate release];
#synchronized(_asyncConnection)
{
[[_asyncConnection objectAtIndex:index] release];
[_asyncConnection replaceObjectAtIndex:index withObject:nullObject];
}
#synchronized(downloadQueue)
{
[downloadQueue removeObject:activeInfo[index]];
[self NextDownload];
}
}
- (void)NextDownload
{
NSLog(#"files remaining: %i", downloadQueue.count);
if(downloadQueue.count > 0)
{
if([self TryDownload:[downloadQueue objectAtIndex:0]])
{
[downloadQueue removeObjectAtIndex:0];
}
}
}
_asyncConnection is my array of download slots (NSURLConnections)
downloadQueue is list of urls to download
What happens is, at the beginning everything works ok, but after few downloads my connections start to disappear. Download starts but connection:didReceiveResponse: never gets called. There is one thing in output console that I don't understand I that might help a bit. Normaly there is something like
2010-01-24 21:44:17.504 appName[3057:207]
before my NSLog messages. I guess that number in square brackets is some kind of app:thread id? everything works ok while there is same number, but after some time, "NSLog(#"downloading %# at index %i", info.url, index);" messages starts having different that second number. And when that happens, I stop receiving any callbacks for that urlconnection.
This has been driving me nuts as I have strict deadlines and I can't find problem. I don't have many experiences with iphone dev and multithreaded apps. I have been trying different approaches so my code is kinda messy, but I hope you will see what I am trying to do here :)
btw is anyone of you know about existing class/lib I could use that would be helpful as well. I want parallel downloads with ability o dynamically add new files to download (so initializing downloader at the beginning with all urls is not helpful for me)
You've got a bunch of serious memory issues, and thread synchronization issues in this code.
Rather than go into them all, I'll ask the following question: You are doing this on a background thread of some kind? Why? IIRC NSURLConnection already does it's downloads on a background thread and calls your delegate on the thread that the NSURLConnection was created upon (e.g., your main thread ideally).
Suggest you step back, re-read NSURLConnection documentation and then remove your background threading code and all the complexity you've injected into this unnecessarily.
Further Suggestion: Instead of trying to maintain parallel positioning in two arrays (and some sketchy code in the above relating to that), make one array and have an object that contains both the NSURLConnection AND the object representing the result. Then you can just release the connection instance var when the connection is done. And the parent object (and thus the data) when you are done with the data.
I recommend that you take a look at this:
http://allseeing-i.com/ASIHTTPRequest/
It's a pretty sophisticated set of classes with liberal licensing terms (free too).
It may provide a lot of the functionality that you are wanting.
This snippet can be the source of the bug, you release the object pointed to by the activeInfo[index].delegate pointer right after issuing async method call on that object.
[(id)activeInfo[index].delegate performSelectorInBackground:#selector(backgroundDownloadSucceededWithData:) withObject:_data[index]];
[_data[index] release];
[activeInfo[index].delegate release];
Do you use connection:didFailWithError: ? There may be a timeout that prevents the successful download completion.
Try to get rid of the #synchronized blocks and see what happens.
The string inside the square brackets seems to be thread identifier as you guessed. So maybe you get locked in the #synchronized. Actually, I don't see a reason for switching thread - all the problematic code should run in the main thread (performSelectorOnMainThread)...
Anyhow, there is no need to use both the #synchronized and the performSelectorOnMainThread.
BTW, I didn't see the NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self]; line. Where do you initiate the connection?
As for the parallel downloads - I think that you can download more than one file in a time with the same code that you use here. Just create a separate connection for each download.
Consider just keeping a download queue along with a count of active connections, popping items off the top of the queue when downloads complete and a slot becomes free. You can then fire off NSURLConnection objects asynchronously and process events on the main thread.
If you find that your parallel approach prohibits doing all of the processing on the main thread, consider having intermediary manager objects between your main thread download code and NSURLConnection. Using that approach, you'd instantiate your manager and get it to use NSURLConnection synchronously on a background thread. That manager then completely deals with the downloading and passes the result back to its main thread delegate using a performSelectorOnMainThread:withObject: call. Each download is then just a case of creating a new manager object when you've a slot free and setting it going.