iphone download indicator not displaying - ios

I download certain data, and when it's downloaded this method is called:
- (void)connectionDidFinishLoading:(NSURLConnection *)connection;
In this method I should present a rotating image in the view controller which I do with delegateing and when the data is downloaded I remove this roatating image:
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
[delegate showIndicator];
//Complex data downloading
[delegate hideIndicator];
}
So those method are called when the connectionFinishedLoading happen, but they are not called. Here are their implementations:
-(void)showIndicator;
{
NSLog(#"Show indicator");
UIImage *statusImage = [UIImage imageNamed:#"update.png"];
activityImageView = [[UIImageView alloc] initWithImage:statusImage];
// Make a little bit of the superView show through
activityImageView.animationImages = [NSArray arrayWithObjects:
[UIImage imageNamed:#"update.png"],
[UIImage imageNamed:#"update2.png"],
[UIImage imageNamed:#"update3.png"],
[UIImage imageNamed:#"update4.png"],
nil];
activityImageView.frame=CGRectMake(13, 292, 43, 44);
activityImageView.animationDuration = 1.0f;
[rightView addSubview:activityImageView];
[activityImageView startAnimating];
}
-(void)hideIndicator
{ NSLog(#"Hide indicator");
[activityImageView removeFromSuperview];
}
And that's where I create JManager object for which connectionFinished event is called:
-(IBAction)update:(id)sender
{
///la la la updating
JManager *manager1=[[JManager alloc] initWithDate:dateString andCategory:#"projects"];
manager1.delegate=self;
[manager1 requestProjects];
}
Why can't my custom indicator adding can't be done on the behalf of Jmanager object? thanks!

Assuming you are calling your NSURLConnection from the main thread, the method is not executed asynchronously, so the indicator has no opportunity to be displayed between you starting and stopping it.
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
[delegate showIndicator];
//Complex data downloading
[delegate hideIndicator];
}
You should call the [delegate showIndicator] in your - (void)connectionDidReceiveResponse method instead, like this:
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
//connection starts
[delegate showIndicator];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
//connection ends
[delegate hideIndicator];
}

Related

iOS - NSURLSession not working the second time

I have a UIView that contains a progress bar. What I want to do is simple, I have a button, user clicks that button, app downloads file and show progress in progress bar. I am able to do this when the user clicks the download button the first time. But when the user clicks the second time to download again, NSURLSession delegates are not called.
My UIView .m
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
[self configure];
}
return self;
}
- (id)initWithCoder:(NSCoder *)aDecoder
{
self = [super initWithCoder:aDecoder];
if (self) {
[self configure];
}
return self;
}
-(void)configure
{
[self createSpinner];
[self createProgressBar];
NSArray *URLs = [[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask];
self.docDirectoryURL = [URLs objectAtIndex:0];
NSURLSessionConfiguration *sessionConfiguration = [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:#"com.tinkytickles"];
sessionConfiguration.HTTPMaximumConnectionsPerHost = 1;
self.session = [NSURLSession sessionWithConfiguration:sessionConfiguration
delegate:self
delegateQueue:nil];
}
-(void)createSpinner
{
[self setBackgroundColor:[UIColor colorWithWhite:1.0f alpha:0.5f]];
spinner = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
[self addSubview:spinner];
[spinner setColor:original_new_dark_grey];
[spinner setUserInteractionEnabled:NO];
[spinner setCenter:CGPointMake([[UIScreen mainScreen] bounds].size.width/2, [[UIScreen mainScreen] bounds].size.height/2)];
[spinner setFrame:CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height)];
[spinner startAnimating];
}
-(void)createProgressBar
{
self.progressBar = [[TYMProgressBarView alloc] initWithFrame:CGRectMake(0, 0, 280, 15)];
[self.progressBar setBarBackgroundColor:[UIColor whiteColor]];
[self.progressBar setBarBorderColor:original_new_dark_grey];
[self.progressBar setBarFillColor:original_new_dark_grey];
[self.progressBar setBarBorderWidth:1.0f];
[self addSubview:self.progressBar];
[self.progressBar setCenter:CGPointMake([[UIScreen mainScreen] bounds].size.width/2, [[UIScreen mainScreen] bounds].size.height/2)];
[self.progressBar setHidden:YES];
self.label = [[UILabel alloc] initWithFrame:CGRectMake(self.progressBar.frame.origin.x, self.progressBar.frame.origin.y - 30, self.progressBar.frame.size.width, 25)];
[self.label setText:NSLocalizedString(locDownloading, nil)];
[self.label setTextAlignment:NSTextAlignmentCenter];
[self.label setTextColor:original_new_dark_grey];
[self.label setFont:quicksand_14];
[self addSubview:self.label];
[self.label setHidden:YES];
}
-(void)showProgressBarWithProgress:(CGFloat)progress withText:(NSString *)text
{
[spinner setHidden:YES];
[self.label setText:[NSString stringWithFormat:NSLocalizedString(locDownloadingAt, nil), text]];
[self.label setHidden:NO];
[self.progressBar setHidden:NO];
[self.progressBar setProgress:progress];
}
-(void)stopAnimating
{
[spinner stopAnimating];
}
-(void)startDownloadingURL:(PromoterDownloadInfo *)downloadInfo
{
info = downloadInfo;
if (!info.isDownloading)
{
if (info.taskIdentifier == -1)
{
info.downloadTask = [self.session downloadTaskWithURL:[NSURL URLWithString:info.downloadSource]];
info.taskIdentifier = info.downloadTask.taskIdentifier;
[info.downloadTask resume];
}
else
{
info.downloadTask = [self.session downloadTaskWithResumeData:info.taskResumeData];
[info.downloadTask resume];
info.taskIdentifier = info.downloadTask.taskIdentifier;
}
}
else
{
[info.downloadTask cancelByProducingResumeData:^(NSData *resumeData) {
if (resumeData != nil) {
info.taskResumeData = [[NSData alloc] initWithData:resumeData];
}
}];
}
info.isDownloading = !info.isDownloading;
}
-(void)stopDownload:(PromoterDownloadInfo *)downloadInfo
{
if (!info.isDownloading)
{
if (info.taskIdentifier == -1)
{
info.downloadTask = [self.session downloadTaskWithURL:[NSURL URLWithString:info.downloadSource]];
}
else
{
info.downloadTask = [self.session downloadTaskWithResumeData:info.taskResumeData];
}
info.taskIdentifier = info.downloadTask.taskIdentifier;
[info.downloadTask resume];
info.isDownloading = YES;
}
[self stopAnimating];
[self removeFromSuperview];
}
#pragma mark - NSURLSession Delegate method implementation
-(void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location
{
NSError *error;
NSFileManager *fileManager = [NSFileManager defaultManager];
NSString *destinationFilename = downloadTask.originalRequest.URL.lastPathComponent;
NSURL *destinationURL = [self.docDirectoryURL URLByAppendingPathComponent:destinationFilename];
if ([fileManager fileExistsAtPath:[destinationURL path]]) {
[fileManager removeItemAtURL:destinationURL error:nil];
}
BOOL success = [fileManager copyItemAtURL:location
toURL:destinationURL
error:&error];
if (success) {
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
[self stopAnimating];
[self removeFromSuperview];
}];
}
else
{
NSLog(#"Unable to copy temp file. Error: %#", [error localizedDescription]);
}
}
-(void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error{
if (error != nil) {
NSLog(#"Download completed with error: %#", [error localizedDescription]);
}
else{
NSLog(#"Download finished successfully.");
}
}
-(void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite
{
if (totalBytesExpectedToWrite == NSURLSessionTransferSizeUnknown) {
NSLog(#"Unknown transfer size");
}
else
{
dispatch_async(dispatch_get_main_queue(), ^{
info.downloadProgress = (double)totalBytesWritten / (double)totalBytesExpectedToWrite;
[self showProgressBarWithProgress:info.downloadProgress withText:info.fileTitle];
});
}
}
-(void)URLSessionDidFinishEventsForBackgroundURLSession:(NSURLSession *)session
{
AppDelegate *appDelegate = (AppDelegate *)[UIApplication sharedApplication].delegate;
// Check if all download tasks have been finished.
[self.session getTasksWithCompletionHandler:^(NSArray *dataTasks, NSArray *uploadTasks, NSArray *downloadTasks) {
if ([downloadTasks count] == 0) {
if (appDelegate.backgroundTransferCompletionHandler != nil) {
// Copy locally the completion handler.
void(^completionHandler)() = appDelegate.backgroundTransferCompletionHandler;
// Make nil the backgroundTransferCompletionHandler.
appDelegate.backgroundTransferCompletionHandler = nil;
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
// Call the completion handler to tell the system that there are no other background transfers.
completionHandler();
// Show a local notification when all downloads are over.
UILocalNotification *localNotification = [[UILocalNotification alloc] init];
localNotification.alertBody = NSLocalizedString(locDownloadComplete, nil);
[[UIApplication sharedApplication] presentLocalNotificationNow:localNotification];
}];
}
}
}];
}
I use this UIView like this:
PromoterDownloadInfo *info = [[PromoterDownloadInfo alloc] initWithFileTitle:self.title andDownloadSource:#"https://www.mywebsite.com/file.zip"];
PromotersDownloadView *downloadView = [[PromotersDownloadView alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
[self.navigationController.view addSubview:downloadView];
[downloadView startDownloadingURL:info];
The first time I clicked the download button it works great. The second time NSURLSession only didCompleteWithError method gets called. Here is what I get from log the second time:
2016-05-12 00:50:47.440 APP[32990:1230071] A background URLSession with identifier com.app already exists!
2016-05-12 00:50:50.614 APP[32990:1230386] Download finished successfully.
What am I doing wrong? I tried to create NSURLSessionConfiguration only once but this way no delegate method gets called. What should I do?
You said:
The first time I clicked the download button it works great. ... Here is what I get from log the second time:
2016-05-12 00:50:47.440 APP[32990:1230071] A background URLSession with identifier com.app already exists!<br />
That error is pointing out that you want to instantiate only one background NSURLSession for a given identifier (and you generally only need/want a single background session). If you were going to instantiate multiple ones, you'd give them unique identifiers, but handling background sessions is complicated enough without unnecessarily having multiple sessions. I'd suggest that you only want a single background session.
You said:
I tried to create NSURLSessionConfiguration only once but this way no delegate method gets called.
Yes, you should have one session configuration. And, just as importantly, only one background session object.
I suspect that there's an issue with your delegate object not being able to keep track of which view it should be updating. Or perhaps you lost reference to your session object and your reference was nil. It could be a couple of different things, and it's hard to know without seeing how you did this.
I'd suggest moving this session configuration code out of the view, and have some shared instance that you can reference anywhere (e.g. a singleton works well, so you can instantiate it from wherever it's first needed, whether from a view or from the app delegate's handleEventsForBackgroundURLSession method).
The only challenge then is how to keep track of which views are keeping track of which network requests. Do you want to have a single view that will keep track of all incomplete requests, regardless of when this view is instantiated? If so, you can use NSNotificationCenter notifications (that way, any view that wants to be notified of progress updates can just observe your custom notification). Or does a given view only care about requests that you initiated from that view?In that case, you might maintain dictionary that maps taskIdentifier values to which view or object needs to know about the status updates (what way you can have your session object keep track of which views care about which tasks). It just depends upon your app's requirements.

How to change a views UILabels, UIButtons, UIViews, etc. from a Multipeer Connectivity Session?

It has been 4 days now, and I have been trying to change the view or elements of a view belonging to a peer connected within a multipeer connectivity session. The session is created and I am able to connect two devices and send data between the two, but whenever I try to change a label nothing happens. When I used NSLog to see what the label.text was, it return null.
Here is my session didReceiveData: method:
- (void)session:(MCSession *)session didReceiveData:(NSData *)data fromPeer:(MCPeerID *)peerID {
NSLog(#"did receive data, %#", peerID.displayName);
NSDictionary *dict = #{
#"data": data,
#"peerID": peerID
};
[[NSNotificationCenter defaultCenter] postNotificationName:#"MCDidReveiveDataNotification" object:nil userInfo:dict];
NSArray *arrayFromData = [NSKeyedUnarchiver unarchiveObjectWithData:data];
NSString *gesture = [arrayFromData objectAtIndex:0];
UILabel *tapLabel = [arrayFromData objectAtIndex:1];
NSString *tapString = tapLabel.text;
[_gestureViewController receivedTap:gesture withLabelText:tapString]; }
I tried sending the UILabel through with the data along with a normal NSString. When I call the gestureViewController method,
receivedTap:gesture withLabelText:tapString
I am able to NSLog the label text, but when I try to set the current viewController's tapGestureLabel to the tapString text, nothing happens.
Here is my receivedTap:gesture withLabelText:tapString method:
- (void)receivedTap:(NSString *)gesture withLabelText:(NSString *)labelText {
NSLog(#"%#", gesture);
NSLog(#"%#", labelText);
self.tapGestureLabel.text = labelText; }
My idea of dispatching onto main thread:
- (void)session:(MCSession *)session didReceiveData:(NSData *)data fromPeer:(MCPeerID *)peerID {
NSDictionary *dict = #{
#"data": data,
#"peerID": peerID
};
[[NSNotificationCenter defaultCenter] postNotificationName:#"MCDidReceiveDataNotification" object:nil userInfo:dict];
NSArray *arrayFromData = [NSKeyedUnarchiver unarchiveObjectWithData:data];
UIImage *image = [arrayFromData objectAtIndex:2];
[self performSelectorOnMainThread:#selector(changeImage:) withObject:image waitUntilDone:NO];
}
My changeImage: selector method:
- (void)changeImage:(UIImage *)image {
[_gestureViewController.imageView setImage:image];
}
session:didReceiveData is called by the Mulitipeer Connectivity Framework from a dedicated thread. You are trying to update a label from this dedicated thread. This is not allowed, you should only access UI elements from the main queue. The solution is to dispatch the piece of code that updates the label to the main queue.
You can do it in receivedTap:withLabelText as follows:
- (void)receivedTap:(NSString *)gesture withLabelText:(NSString *)labelText {
NSLog(#"%#", gesture);
NSLog(#"%#", labelText);
dispatch_async(dispatch_get_main_queue(), ^{
self.tapGestureLabel.text = labelText;
});
}
Or deal with it earlier in session:didReceiveData:fromPeer
dispatch_async(dispatch_get_main_queue(), ^{
[_gestureViewController receivedTap:gesture withLabelText:tapString];
});

how to get downloading status of video when go back to previous controller and again came back?

Hai here Am downloading a video and storing it to documents folder in iphone... but when i click on download button video will start downloading and progress will show nicely... but when i go back to previous view controller and came back to the downloading controller during downloading the progress view status will not show the current status... can anybody help me to solve this? thanks in advance...
Here is my code...
- (void)downLoad:(UIButton *)sender {
_downloadBtn.hidden = YES;
_videoData = [[NSMutableData alloc] init];
_resourceName = [_resourceNameArray objectAtIndex:sender.tag];
_resourceType = [_contentTypesArray objectAtIndex:sender.tag];
NSString *urlStr = [NSString stringWithFormat:#"%#",[_videoUrlArray objectAtIndex:sender.tag]];
[NSURLConnection connectionWithRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:urlStr]] delegate:self ];
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
NSLog(#"Downloading Started");
_length = [response expectedContentLength];
NSLog(#"Size:%0.2f",_length);
}
-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
[_videoData appendData:data];
float progress = (float)[_videoData length]/(float)_length;
NSLog(#"Progress:%0.2f",progress);
//_timeLabel.text = [NSString stringWithFormat:#"%0.2F%%",progress*100];
[_progressView setProgress:progress animated:YES];
}
-(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
NSLog(#"didFailWithError");
}
-(void)connectionDidFinishLoading:(NSURLConnection *)connection {
[self saveLocally:_videoData res:_resourceName type:_resourceType];
NSLog(#"File Saved !");
}
Download screen -> previous screen -> Download screen. Let's try:
-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
[_videoData appendData:data];
float progress = (float)[_videoData length]/(float)_length;
NSLog(#"Progress:%0.2f",progress);
NSNumer *n = [NSNumber numberWithFloatValue:progress];
[[NSNotificationCenter defaultCenter] postNotificationName:NOTIFICATION_DOWNLOAD_PROGRESS object:n];
//_timeLabel.text = [NSString stringWithFormat:#"%0.2F%%",progress*100];
[_progressView setProgress:progress animated:YES];
}
When you go back to download screen, you should update progress by receive notification
#define NOTIFICATION_DOWNLOAD_PROGRESS #"NOTIFICATION_DOWNLOAD_PROGRESS"
- (void)viewDidLoad
{
[super viewDidLoad];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(processProgressBar:) name:NOTIFICATION_DOWNLOAD_PROGRESS object:nil];
}
- (void) processProgressBar:(NSNumber *) progress
{
[_progressView setProgress: progress.floatValue];
}

Integrating MBProgressHUD with two classes

Im am trying to properly integrate MBProgressHUD in a project while i am downloading and processing some data. Forgive me my ignorance if i am asking stupid things, but i'm a complete noob...
I have a "Data" class that is handling my HTTPRequests, so i thing here is the proper place to put some stuff in:
-(void)resolve
{
// Create the request.
NSURLRequest *theRequest=[NSURLRequest requestWithURL:[[NSURL alloc] initWithString:[self url]]
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:60.0];
NSLog(#"Resolving content from: %#",[self url]);
// create the connection with the request
// and start loading the data
NSURLConnection *theConnection=[[NSURLConnection alloc] initWithRequest:theRequest delegate:self];
if (theConnection) {
// Create the NSMutableData to hold the received data.
// receivedData is an instance variable declared elsewhere.
receivedData = [[NSMutableData data] retain];
} else {
NSLog(#"Content - resolve: connection failed");
}
// Here is the part that it makes me crazy...
HUD = [[MBProgressHUD showHUDAddedTo:self.view animated:YES] retain];
return;
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
// This method is called when the server has determined that it
// has enough information to create the NSURLResponse.
// It can be called multiple times, for example in the case of a
// redirect, so each time we reset the data.
// receivedData is an instance variable declared elsewhere.
expectedLength = [response expectedContentLength];
currentLength = 0;
HUD.mode = MBProgressHUDModeDeterminate;
[receivedData setLength:0];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
currentLength += [data length];
HUD.progress = currentLength / (float)expectedLength;
// Append the new data to receivedData.
// receivedData is an instance variable declared elsewhere.
[receivedData appendData:data];
return;
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
[HUD hide:YES];
// release the connection, and the data object
[connection release];
// receivedData is declared as a method instance elsewhere
[receivedData release];
// inform the user
NSLog(#"Content - Connection failed! Error - %# %#",
[error localizedDescription],
[[error userInfo] objectForKey:NSURLErrorFailingURLStringErrorKey]);
return;
}
Now i know that putting the "showHUDaddedTo" in the -(void)resolve is not the right way...
I am calling this data function from a view controller with an IBaction like this:
-(IBAction) btnClicked:(id) sender {
if ([[issue status] intValue] == 1 ) // issue is not downloaded
{
[(Content *)[issue content] resolve];
//HUD = [[MBProgressHUD showHUDAddedTo:self.navigationController.view animated:YES] retain];
}
else // issue is downloaded - needs to be archived
{
NSError * error = nil;
[[NSFileManager defaultManager] removeItemAtPath:[(Content *)[issue content] path] error:&error];
if (error) {
// implement error handling
}
else {
Content * c = (Content *)[issue content];
[c setPath:#""];
[issue setStatus:[NSNumber numberWithInt:1]];
[buttonView setTitle:#"Download" forState:UIControlStateNormal];
[gotoIssue setTitle:#"..." forState:UIControlStateNormal];
// notify all interested parties of the archived content
[[NSNotificationCenter defaultCenter] postNotificationName:#"contentArchived" object:self]; // make sure its persisted!
}
}
}
Simply said: i would like to call all the MBProgressHUD stuff from my Conten.m file in the moment i push the download button in my IssueController.m file. I think you see now where my problem is: i am not a coder ;-) Any help is appreciated.
Cheers,
sandor
I would try and use the HUD method showWhileExecuting. Wrap your calls up in a new method and call that to download your information. When your method finishes, so will your HUD.
Also, is there a reason why you are retaining your calls for the HUD? I have not seen that before and I'm not sure if you need to retain those as they are autoreleased.

How to make sure I have only 1 asynchronous NSURLConnection at a time?

I'm creating an app which communicates alot with a server. I want to make sure I have only 1 connection at a time - only 1 request pending. I want so that if I try to send another request, It will wait until the current one is finished before sending the next.
How can I implement This?
Tnx!
I don't know of any automatic mechanism to do this. So you have to write a new class yourself (let's call it ConnectionQueue):
Basically, instead of a creating the NSURLConnection directly, you call a method of your ConnectionQueue class (which should have exactly one instance) taking the NSURLRequest and the delegate as a parameter. Both are added to a queue, i.e. a separate NSArray for the requests and the delegates.
If the arrays contains just one element, then no request is outstanding and you can create a NSURLConnection with the specified request. However, instead of the delegate passed to the method, you pass your ConnectionQueue instance as the delegate. As a result, the connection queue will be informed about all actions of the connection. In most cases, you just forward the callback to the original delegate (you'll find it in the first element of the delegate array).
However, if the outstanding connection completes (connection:didFailWithError: or connectionDidFinishLoading: is called), you first call the original delegate and then remove the connection from the two arrays. Finally, if the arrays aren't empty, you start the next connection.
Update:
Here's some code. It compiles but hasn't been tested otherwise. Furthermore, the implementation of the NSURLConnectionDelegate protocol is incomplete. If you're expecting more than implemented callbacks, you'll have to add them.
Header File:
#import <Foundation/Foundation.h>
#interface ConnectionQueue : NSObject {
NSMutableArray *requestQueue;
NSMutableArray *delegateQueue;
NSURLConnection *currentConnection;
}
// Singleton instance
+ (ConnectionQueue *)sharedInstance;
// Cleanup and release queue
+ (void)releaseShared;
// Queue a new connection
- (void)queueRequest:(NSURLRequest *)request delegate:(id)delegate;
#end
Implementation:
#import "ConnectionQueue.h"
#implementation ConnectionQueue
static ConnectionQueue *sharedInstance = nil;
+ (ConnectionQueue*)sharedInstance
{
if (sharedInstance == nil)
sharedInstance = [[ConnectionQueue alloc] init];
return sharedInstance;
}
+ (void)releaseShared
{
[sharedInstance release];
sharedInstance = nil;
}
- (id)init
{
if ((self = [super init])) {
requestQueue = [NSMutableArray arrayWithCapacity:8];
delegateQueue = [NSMutableArray arrayWithCapacity:8];
}
return self;
}
- (void)dealloc
{
[requestQueue release];
[delegateQueue release];
[currentConnection cancel];
[currentConnection release];
[super dealloc];
}
- (void)startNextConnection
{
NSURLRequest *request = [requestQueue objectAtIndex:0];
currentConnection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
}
- (void)queueRequest:(NSURLRequest *)request delegate:(id)delegate
{
[requestQueue addObject:request];
[delegateQueue addObject:delegate];
if ([requestQueue count] == 1)
[self startNextConnection];
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
id delegate = [delegateQueue objectAtIndex:0];
[delegate connection: connection didReceiveResponse: response];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
id delegate = [delegateQueue objectAtIndex:0];
[delegate connection: connection didReceiveData: data];
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
id delegate = [delegateQueue objectAtIndex:0];
[delegate connection: connection didFailWithError:error];
[currentConnection release];
currentConnection = nil;
[requestQueue removeObjectAtIndex:0];
[delegateQueue removeObjectAtIndex:0];
if ([requestQueue count] >= 1)
[self startNextConnection];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
id delegate = [delegateQueue objectAtIndex:0];
[delegate connectionDidFinishLoading: connection];
[currentConnection release];
currentConnection = nil;
[requestQueue removeObjectAtIndex:0];
[delegateQueue removeObjectAtIndex:0];
if ([requestQueue count] >= 1)
[self startNextConnection];
}
#end
To use the connection queue, create an NSURLRequest instance and then call:
[[ConnectionQueue sharedInstance] queueRequest:request delegate:self];
There's no need to create the singleton instance of ConnectionQueue explicitly. It will be created automatically. However, to properly clean up, you should call [ConnectionQueue releaseShared] when the application quits, e.g. from applicationWillTerminate: of your application delegate.

Resources