1

I have an API that gets me the file URL to download. I am using NSURLConnection to download the file. The file size could be a little big because it's an MP4.

Code Steps:

  1. Initialized NSMutableURLRequest and added HttpHeaderField to it with the byte index I want to resume download from. (I do this because internet connection could be lost).

  2. Initialized NSURLConnection with the NSMutableURLRequest.

  3. Used connection:didReceiveData: to receive data segments and append it to a global NSMutableData object.

  4. An error message could be generated because of an internet problem and it's handled using connection:didFailWithError:. In this handler I setText the download status label with the message "No internet connectivity, or it is very slow". Sleep for 1 second and then go back to step one again.

Code:

- (void)viewDidLoad
{
    [super viewDidLoad];
    [self resumeDownload];
}

- (void)resumeDownload
{
    NSURL *url = [NSURL URLWithString:video->videoUrl];
    NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url];
    if (receivedData==nil)
    {
        receivedData = [[NSMutableData alloc] init];
    }
    else
    {
        NSString *range = [NSString stringWithFormat:@"bytes=%i-", receivedData.length];
        [request setValue:range forHTTPHeaderField:@"Range"];
    }

    downloadConnection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
}

- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
    NSLog(@"%@", [response description]);
}

- (void) connection:(NSURLConnection*)connection didFailWithError:(NSError*) error
{
    NSLog(@"Download Fail : %d", [error code]);
    [status setText:@"No internet conectivity or it is very slow."];
    sleep(1);
    [self resumeDownload];
}

- (void) connectionDidFinishLoading:(NSURLConnection*)connection
{
    // save the file
}

- (void) connection: (NSURLConnection*) connection didReceiveData: (NSData*) data
{
    if(connection == downloadConnection)
    {
        [receivedData appendData:data];
        [status setText:[NSString stringWithFormat:@"Downloading: %d Bytes.", receivedData.length]];
    }
}

Screen Shots:

enter image description here enter image description here

Note: When the internet reconnects, the download will resume automatically.

Is this a proper solution for the problem?

Neeku
  • 3,646
  • 8
  • 33
  • 43
hasan
  • 23,815
  • 10
  • 63
  • 101
  • I will let the app to try to connect again in 10 seconds, with a count down indicator, "Download will be resumed in 6s". and I will add a button to for force resume. – hasan Nov 08 '12 at 09:27

1 Answers1

1

All in all - you're on the right path.
You should check the kind of errors you get - if there's no network, there's no point trying again, you should use a reachability test to find out when to try again.
You should also check the response type - 4xx / 5xx will not return a connection failure even though this is a failure for you, for example - 502 error means you should try a bit later, even though the connection finished successfully.
I'd avoid using sleep - you're blocking the main thread.
Either use performSelector:withObject:afterDelay or use an NSTimer.
Oh, and one second seems too short to me.

Moshe Gottlieb
  • 3,963
  • 25
  • 41
  • 502 Bad Gateway The server was acting as a gateway or proxy and received an invalid response from the upstream server. Are you sure that dont return an error to connection:didFailWithError: ? – hasan Nov 08 '12 at 08:45
  • 1
    @hasan - 502 error is a "logical" error. the response can still be valid and informative and therefore `didFailWithError` will not be called for it. Otherwise, how would you be able to get the data from 5xx/4xx responses? you need to check the response type using `connection:didReceiveResponse:`. – Moshe Gottlieb Nov 08 '12 at 10:31
  • Thank you for help so far. How my app. is acting towards 5xx errors (the code that is written so far)? Is it going to continue downloading normally and finish file download with a missing segments or what? Can you provide me with a partial code that handles 5xx errors? Thank you. – hasan Nov 09 '12 at 16:52
  • 1
    You need to implement `- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response`, cast response into `NSHTTPURLResponse` (only for HTTP requests, of course) and it to find out what is the status code, etc. If the status code isn't 2xx (or 3xx) you should probably cancel the connection. Depending on the status, you may want to try the download again later. – Moshe Gottlieb Nov 10 '12 at 16:50