IPHONE SDK : NSURLConnection asynchronous / wait completion bug ?
I am trying to use NSURLConnection in asynchronous mode and wait for completion. During the wait, I use NSRUNLOOP to handle events. Its works in most cases (3G and WIFI) but the application hangup randomly in GSM DATA and EDGE environment.
My code:
(void) connectionDidFinishLoading:(NSURLConnection *)connection
{
_requestCompleted = TRUE;
CFRunLoopStop(CFRunLoopGetCurrent());
}
(void) connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
_response = (NSHTTPURLResponse *)response;
[ _response retain];
}
(void) connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
/* Append the new data to the received data. */
[_receivedData appendData:data];
}
(void) connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
_requestError = error;
NSLog(@"request error - cause : %@", [_requestError localizedDescription ]);
_requestCompleted = TRUE;
[_requestError retain];
CFRunLoopStop(CFRunLoopGetCurrent());
}
(NSString*)downloadFileFromURL:(NSString*)url
{
NSURLRequest *request = nil;
NSString *contents = nil;
NSData *response = nil;
int tries;
NSURLConnection *URLConnection = nil;
int i = 0;
NSDate* dateLimit;
[_mutex lock];
NSLog(@"url = %@", url);
NSString *requestWithEscaping = [ url stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding ];
request = [NSURLRequest requestWithURL:[NSURL URLWithString:requestWithEscaping]
cachePolicy: NSURLRequestReloadIgnoringLocalCacheData
timeoutInterval:30];
for (tries = 0; tries < HTTP_REQUESTS_TRIES && response == nil ; tries ++) {
[_receivedData setLength:0];
_requestCompleted = FALSE;
_requestError = nil;
_requestTimeout = FALSE;
if (URLConnection == nil)
URLConnection = [ NSURLConnection connectionWithRequest:request delegate:self];
else {
[URLConnection cancel ];
[URLConnection start];
}
if (URLConnection == nil) {
NSLog(@"No connection ! maybe mistake in Request Format ?");
continue;
}
for (i = 0; ; i++) {
dateLimit = [[NSDate date] addTimeInterval:INTERVALL_LOOP];
[ [NSRunLoop currentRunLoop] runUntilDate:dateLimit];
if (_requestCompleted == TRUE)
break;
if (i > (int)(HTTP_TIMEOUT_FIRE * (1 / INTERVALL_LOOP))) {
_requestTimeout = TRUE;
break;
}
}
if (_requestTimeout) {
[ URLConnection cancel];
NSLog(@"request timeout");
continue;
}
if (_requestError) {
NSLog(@"request error");
continue;
}
NSLog(@"Request success");
break;
}
if (_requestTimeout) {
_lastErrorType = ServicesRequestManager_error_Network;
[ _lastErrorString setString:@"Délai de connexion depassé"];
[ _mutex unlock];
return nil;
}
if (_requestError) {
NSLog(@"ERROR Cannot get %@ - cause : %@",url, [ _requestError localizedDescription ]);
_lastErrorType = ServicesRequestManager_error_Network;
[_lastErrorString setString:@"Impossible de se connecter" ];
[ _mutex unlock];
return nil;
}
if ([ _response statusCode] != 200 ) {
NSLog(@"ERROR Download file %@ HTTP response - code : %d", url, [ _response statusCode]);
[_lastErrorString setString:[ NSString stringWithForm开发者_开发百科at:@"Error http code : %d", [_response statusCode]]];
_lastErrorType = ServicesRequestManager_error_Service;
[_lastErrorString setString:@"Le service n'est pas disponible actuellement" ];
[ _mutex unlock];
return nil;
}
contents = [[NSString alloc] initWithData:_receivedData encoding:NSUTF8StringEncoding];
[ _mutex unlock];
return contents;
}
NSURLConnection is already asynchronous. Simply implement the delegate methods. If you want to update the UI on the MainThread (e.g. a progress bar), you can do so in didReceiveData
.
I use NSNotification
or that puspose. In DidFinishLoading method post a notification,
[[NSNotificationCenter defaultCenter] postNotificationName:@"Name" object:someObject];
and handle this notification in anyclass by
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleMethod:) notificationName:@"Name" object:nil];
and implement
-(void)handleMethod:(NSNotification *)ntf
精彩评论