3

I've edited this post to make it simpler to read, I think.

I need to call an NSUrlConnection after I've finished doing some intensive string manipulation in a dispatch_async block.

The URL I call has got .htaccess authentication on it, so I can't use a synchronous connection.

But the NSURLConnection delegate methods are not being called. I know the URL loads after about 5 seconds in the browser, and I've tested the code with a simple URL with no authentication and it makes no difference.

What is stopping the delegate methods being called?

This function does some string manipulation stuff, and takes a while to finish:

- (void)performSearch {

    // set some defaults and work out if it is a valid search, setting bSearchOk

    if (bSearchOk) {

        // update some interface elements
        self.msgBox.text = @"Translating...";            
        self.plateInput.enabled = NO;
        self.searchProgress.hidden = NO;

        dispatch_async( dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

            // create a new search
            Search *oPlateSearch = [[Search alloc] initWithTerm:thisTerm];

            // ...
            // perform search... this calls a variety of slow and intensive functions
            // ...

            self.aFinalPlates = [oPlateSearch.aValidated copy];
            self.aCurrentPlates = [oPlateSearch.aFinals copy];        

            dispatch_async( dispatch_get_main_queue(), ^{                 
                [oPlateSearch release];              

                // make ajax call to check if plates can be bought
                [self getPrices];                 
            });
        });

    } else {
        // hide results
        self.searchResults.hidden = YES;
    }

}

And this is the one called towards the end of the block above

/* call to get plate availability and prices */
-(void) getPrices {
    // set return message
    self.msgBox.text = @"Getting prices and availability";

    // ...
    // then I build my strRequest var, which is a valid working URL
    // ...

    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:strRequest]];

    NSURLConnection *loginConnection = [[[NSURLConnection alloc] initWithRequest:request delegate:self] autorelease];

    NSLog('This will get logged');

    if(loginConnection) {
        NSLog('This will also get logged');
        self.jsonSearchResponse = [[[NSMutableData data] retain] autorelease];
        NSLog('And this will get logged, so it's not throwing errors');
    } else {
        NSLog(@"Failed to get search results");
    }
}

Update: I've tried this as well, as it was an accepted in answer on another similar question, but it hasn't worked:

NSURLConnection *loginConnection = [[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:NO];
[loginConnection scheduleInRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes];
[loginConnection start];

Based on this question: Why NSURLConnection delegate methods don't get called, when using the global dispatch queue?

Community
  • 1
  • 1
Pete
  • 4,542
  • 9
  • 43
  • 76

3 Answers3

4

I have started a SO post which shows how to use the NSURLConnection with dispatch_async and configure the NSRunLoop

NSURLConnection blocking wrapper implemented with semaphores

The piece of code that you would be interested in is:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    NSURLRequest* request = [NSURLRequest requestWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:10];
    [NSURLConnection connectionWithRequest:request delegate:self];

    while(!self.finished) {
        [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
    }
});

and in the connectionDidFinishLoading, set finished to YES:

- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
    self.finish = YES;
}
Community
  • 1
  • 1
quentinadam
  • 3,058
  • 2
  • 27
  • 42
4

Someone from iphonedevsdk.com forum answered this for me:

http://www.iphonedevsdk.com/forum/iphone-sdk-development/97415-dispatch_async-nsurlconnection.html

The answer was to use:

 [self performSelectorOnMainThread:@selector(getPrices) withObject:Nil waitUntilDone:NO];
Pete
  • 4,542
  • 9
  • 43
  • 76
  • Why does this fix the problem? – Rey Gonzales Jan 31 '13 at 16:16
  • 1
    I'm not entirely sure, but judging by the function name "performSelectorOnMainThread", when the thread I trigger finishes, it calls a method on the main program thread. – Pete Feb 01 '13 at 12:47
  • 1
    Could it be that you really didn't solve the problem because your calling getPrices on the main thread now and not on the global dispatch queue as you originally desired? – Jon Conner Sep 06 '13 at 23:28
0

I think you're autoreleasing the connection and not keeping any references to it, so that it goes out of memory. Remove the autorelease call and see if the problem disappears. If it does, just find a way to release the connection when you're done with it, so that it does not leak.

zoul
  • 102,279
  • 44
  • 260
  • 354
  • I've tried that, didn't work I'm afraid. I moved the release into the connectionDidFinishLoading and connectionDidFail methods, but it runs in exactly the same way – Pete Jan 20 '12 at 13:59