简体   繁体   中英

NSURLConnection delegate methods are not being called

I am trying to download a set of files from a web server using NSURLConnection but at the point the connection appears to be made, the connection's delegate methods never get fired and so the file never gets downloaded. I have read many answers on SO and other sources and have tried the fixes that have been advised but to no avail, which makes me think I have made a different mistake here.

I have a viewController (InitViewController.m) which loads another class's method:

GetData *getDataInstance = [[GetData alloc] init];
[getDataInstance startUpdate]; 

GetData.m then does some checking and runs the class in charge of getting the files:

GetFiles *getFilesInstance = [[GetFiles alloc] init];
[getFilesInstance doFilesNeedDownloading];

doFilesNeedDowngoading method checks to see if we need the file and then runs getFiles:

-(void)getFile//:(NSString *) fullURL
{

    // I have checked if the connection is run on the main thread and it is
    NSLog(@"Is%@ main thread", ([NSThread isMainThread] ? @"" : @" NOT"));

    NSURL *downloadURL = [NSURL URLWithString:fullURL];

    NSMutableURLRequest *dlRequest = [NSMutableURLRequest requestWithURL:downloadURL];
    NSURLConnection *theConnection = [[NSURLConnection alloc] initWithRequest:dlRequest delegate:self];

    [theConnection scheduleInRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];

    [theConnection start];

    if(theConnection) { //me checking for connection which is 'true'
        NSLog(@"Connection for %@ worked", fullURL);
    } else {
        NSLog(@"Connection for %@ failed", fullURL);
    }

}
-(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {

    responseData = [[NSMutableData alloc] init];
    NSString *fileName = [[NSURL URLWithString:fullURL] lastPathComponent];
    NSString *filePath = [[NSSearchPathForDirectoriesInDomains(NSDocumentationDirectory, NSUserDomainMask, YES) objectAtIndex:0]stringByAppendingPathComponent:fileName];
    [[NSFileManager defaultManager] createFileAtPath:filePath contents:nil attributes:nil];
    file = [NSFileHandle fileHandleForUpdatingAtPath:filePath];
    [file seekToEndOfFile];

}
-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {

    [responseData appendData:data];
    [file seekToEndOfFile];
    [file writeData:data];

}
-(void)connectionDidFinishLoading:(NSURLConnection *)connection {

    [file closeFile];

}

I did originally fire the getDataInstance startUpdate in a separate thread in an update to have the 'getting data' part of the app separate to the 'UI building' part of the app and thought this might be the issue but for now I have remove that and even put in'[theConnection scheduleInRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode]' as per other answers to this kind of question on SO.

I'm sure there will be something really obvious that I have missed, any ideas?

Thanks,

EDIT

I have now tried this code again but in the initViewController so this is pretty much the first thing that is fired when the app loads. This is no longer in another class or thread etc.:

-(void)getFile
{
    fullURL = @"http://myURL.com/terms-and-conditions.txt";
    NSURL *downloadURL = [NSURL URLWithString:fullURL];
    NSMutableURLRequest *dlRequest = [NSMutableURLRequest requestWithURL:downloadURL];
    NSURLConnection *theConnection = [[NSURLConnection alloc] initWithRequest:dlRequest delegate:self];

    [theConnection start];
}
-(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {

    responseData = [[NSMutableData alloc] init];
    NSString *fileName = [[NSURL URLWithString:fullURL] lastPathComponent];
    NSString *filePath = [[NSSearchPathForDirectoriesInDomains(NSDocumentationDirectory, NSUserDomainMask, YES) objectAtIndex:0]stringByAppendingPathComponent:fileName];
    [[NSFileManager defaultManager] createFileAtPath:filePath contents:nil attributes:nil];
    file = [NSFileHandle fileHandleForUpdatingAtPath:filePath];
    [file seekToEndOfFile];   
}
-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {

    [responseData appendData:data];
    [file seekToEndOfFile];
    [file writeData:data];
}
-(void)connectionDidFinishLoading:(NSURLConnection *)connection {

    [file closeFile];
}

getFile gets fired but it's delegate methods still don't get fired?

If you create NSURLConnection in other thread you have to manually start the run loop.

Try with this:

-(void)getFile
{

NSURL *downloadURL = [NSURL URLWithString:fullURL];

NSMutableURLRequest *dlRequest = [NSMutableURLRequest requestWithURL:downloadURL];
NSURLConnection *theConnection = [[NSURLConnection alloc] initWithRequest:dlRequest delegate:self];

[theConnection scheduleInRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
[[NSRunLoop currentRunLoop] run]; 
[theConnection start];

if(theConnection) { //me checking for connection which is 'true'
    NSLog(@"Connection for %@ worked", fullURL);
} else {
    NSLog(@"Connection for %@ failed", fullURL);
}

}

I had this problems too when I wanted to start NSURLConnection in a concurrent NSOperation. Performing connection on main thread helped me solve the problem.

- (void)start {

    if (![NSThread isMainThread]) {
        [self performSelectorOnMainThread:@selector(start)
                               withObject:nil
                            waitUntilDone:NO];
        return;
    }
}

Also scheduling sonnection in [NSRunLoop currentRunLoop] helped me to solve the problem:

self.connection = [[NSURLConnection alloc] initWithRequest:request
                                                  delegate:self
                                          startImmediately:NO];
[self.connection scheduleInRunLoop:[NSRunLoop currentRunLoop]
                           forMode:NSRunLoopCommonModes];
[self.connection start];

You can take a look how it's done in CSMessage class that is part of CSUtils framework. Feel free to use given code on your own: https://github.com/cloverstudio/CSUtils

将委托放在您的class.h中,例如:

@interface InitViewController : UIViewController<NSURLConnectionDelegate,NSURLConnectionDataDelegate>

In the end I re-wrote the whole class and got the delegates firing.

NSString *currentURL = [NSString stringWithFormat:@"%@/api/sync", apiURL];
NSLog(@"URL = %@", currentURL);
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:currentURL]];
[request addValue:@"application/json" forHTTPHeaderField:(@"Accept")];
NSURLResponse *response = nil;
NSError *error = nil;
NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];

Here are the delegates that now fire:

- (void)connection:(FileURLConnection*)connection didReceiveResponse:(NSURLResponse *)response
{
    NSString *fileName = [[response URL] lastPathComponent];
    NSString *filePath = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0]stringByAppendingPathComponent:fileName];
    [[NSFileManager defaultManager] createFileAtPath:filePath contents:nil attributes:nil];
    connection.file = [NSFileHandle fileHandleForUpdatingAtPath:filePath];
}
- (void)connection:(FileURLConnection *)connection didReceiveData:(NSData *)data
{
    [connection.file writeData:data];
}
- (NSCachedURLResponse *)connection:(FileURLConnection *)connection willCacheResponse:(NSCachedURLResponse*)cachedResponse
{
    return nil;
}
- (void)connectionDidFinishLoading:(FileURLConnection *)connection
{
    [connection.file closeFile];
}
- (void)connection:(FileURLConnection *)connection didFailWithError:(NSError *)error
{
    NSLog(@"GetFiles - didFailWithError - error : %@ for URL %@", error, connection.currentRequest.URL);
}

The class now downloads the file (from my own API) and saves it on the device.

Just change this line and rest keep as it is in your code. Keep the scheduleInRunLoop line also.

NSURLConnection * connection = [[NSURLConnection alloc] initWithRequest:request
                                                               delegate:self startImmediately:NO];

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM