Jacob
Jacob

Reputation: 1310

Method gets called two times

I am doing a NSURLConnection that downloads a file only if there is a new one (checked with the last-modified date). But to accomplish this I am using two methods with two different NSURLRequests and NSURLConnection. Well, they do the same.

    - (IBAction)uppdatera:(id)sender
{
    checkHeaders = YES;

    NSURLRequest *theRequest = [NSURLRequest requestWithURL:[NSURL URLWithString:@"http://www.forellgatan.se/site/ftp_files/Kapareskolan.zip"] cachePolicy:NSURLRequestReloadIgnoringLocalCacheData timeoutInterval:10.0];

    NSURLConnection *theConnection = [[NSURLConnection alloc] initWithRequest:theRequest delegate:self];

    if (theConnection) 
    {
        self.receivedData = [[NSMutableData data] retain];
    } 

    else
    {
        UIAlertView *connectFailMessage = [[UIAlertView alloc] initWithTitle:@"Ingen internetanslutning! 1" message:@"Anslut dig till internet för att ladda ner!"  delegate: self cancelButtonTitle:@"Ok" otherButtonTitles: nil];
        [connectFailMessage show];
        [connectFailMessage release];        
    }
}

- (void)downloadNewFile
{
    NSURLRequest *theRequest = [NSURLRequest requestWithURL:[NSURL URLWithString:@"http://www.forellgatan.se/site/ftp_files/Kapareskolan.zip"] cachePolicy:NSURLRequestReloadIgnoringLocalCacheData timeoutInterval:10.0];

    NSURLConnection *theConnection2 = [[NSURLConnection alloc] initWithRequest:theRequest delegate:self];

    if (theConnection2) 
    {
        self.receivedData = [[NSMutableData data] retain];
    } 

    else
    {
        UIAlertView *connectFailMessage = [[UIAlertView alloc] initWithTitle:@"Ingen internetanslutning! 2" message:@"Anslut dig till internet för att ladda ner!"  delegate: self cancelButtonTitle:@"Ok" otherButtonTitles: nil];
        [connectFailMessage show];
        [connectFailMessage release];        
    }

    checkHeaders = NO;

    self.progressView.hidden = NO;
}

It goes through the didReceiveResponse method:

- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
    if (checkHeaders == YES)
    {
        NSHTTPURLResponse *test = (NSHTTPURLResponse *)response;

        if ([test respondsToSelector:@selector(allHeaderFields)])
        {
            NSDictionary *metaData = [test allHeaderFields];

            NSString *lastModifiedString = [metaData objectForKey:@"Last-Modified"];

            NSString *savedString = [[NSUserDefaults standardUserDefaults] stringForKey:@"LastModified"];

            if (![lastModifiedString isEqualToString:savedString])
            {
                [self downloadNewFile];
            }

            else if ([lastModifiedString isEqualToString:savedString])
            {       
                UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Ingen uppdatering tillgänglig" message:@"Det finns ingen uppdatering att hämta just nu." delegate:self cancelButtonTitle:@"Ok" otherButtonTitles:nil];
                [alert show];
                [alert release];
            }

            NSUserDefaults *standardUserDefaults = [NSUserDefaults standardUserDefaults];
            [standardUserDefaults setObject:lastModifiedString forKey:@"LastModified"];
            [standardUserDefaults synchronize];
        }
    }

    [self.receivedData setLength:0];
    self.fileSize = [[NSNumber numberWithLong: [response expectedContentLength]] retain];
}

Last the connectionDidFinishLaunching method:

    - (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
    if (checkHeaders == NO)
    {
        NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
        NSString *basePath = ([paths count] > 0) ? [paths objectAtIndex:0] : nil;
        [self.receivedData writeToFile:[basePath stringByAppendingPathComponent:@"Kapareskolan.zip"] atomically:YES];

        [self unzipDownloadedFile];

        self.progressView.hidden = YES;

        NSLog(@"Finished...");
    }

    [connection cancel];
}

I know the didFinishLaunching method gets called twice, but I want to know how I could get so the method doesn't get called twice if there is an update?

I know it's a lot asked and much code here but just give me a hint and I'll be very thankful.

Upvotes: 0

Views: 1800

Answers (2)

jstevenco
jstevenco

Reputation: 2953

According to the programming guide, a connection "can be canceled any time before the delegate receives a connectionDidFinishLoading: or connection:didFailWithError: message by sending the connection a cancel message".

so why not try moving

      [connection cancel];

from the connectionDidFinishLoading method to just after your if-else block in the didReceiveResponse delegate method? You want to cancel the "checkHeaders==YES" connection in either case; either you're about to kick off a new connection, or you already know all you need to know about the current connection.

UPDATED as requested:

  if (![lastModifiedString isEqualToString:savedString]) {
      [self downloadNewFile];
  } else { // you've already implicitly checked for equality above
      UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Ingen uppdatering tillgänglig" message:@"Det finns ingen uppdatering att hämta just nu." delegate:self cancelButtonTitle:@"Ok" otherButtonTitles:nil];
      [alert show];
      [alert release];
  }
  // you've used the connection for everything that you need, so cancel it in either case
  [connection cancel];

as downloadNewFile kicks off its NSURLConnection asynchronously, this should be okay in the event that the two strings are equal. Slightly safer would be to move the cancel method call to just prior to the if-else check.

Upvotes: 1

Jonathan
Jonathan

Reputation: 1241

If you're done with the first connection object in the didReceiveResponse method you should cancel it then. Otherwise it's going to make it to the connectionDidFinishLoading method. I think this is what you want:

if (![lastModifiedString isEqualToString:savedString])
  {
    [connection cancel];
    [self downloadNewFile];
  }

Also It looks like you're setting checkHeaders to NO after you start the second request which could cause a race condition.

Upvotes: 2

Related Questions