Загрузка с помощью NSURLConnection возвращает пустые данные?

Мое приложение загружает файл из Интернета с помощью NSURLConnection.

Возникают две проблемы:

1) [соединение didReceiveData] никогда не вызывается

2) Когда вызывается [connection didFinishDownloading], мой self.currentData пуст

Что я делаю неправильно?

Мой заголовок выглядит так:

@interface DIFileDownloader : NSObject <NSURLConnectionDelegate> {

    NSMutableData *currentData;

}

@property (nonatomic, assign) id <DIFileDownloaderDelegate> delegate;

@property (nonatomic, retain) NSMutableArray *supportedFormats;

@property (nonatomic, retain) NSMutableData *currentData;

@property (nonatomic, retain) NSURLConnection *downloadAgent;

@property (nonatomic) long long expectedContentSize;

@property (nonatomic) float currentDownloadProgress;

@property (nonatomic, getter = isRunning) BOOL running;

-(instancetype)initWithSupportedFormats:(NSArray *)extensions;

-(void)downloadFileAtURL:(NSURL *)url;

-(NSString *)documentsDirectoryPath;

@end

И мой файл реализации:

-(instancetype)initWithSupportedFormats:(NSArray *)extensions {

    self.supportedFormats = [[NSMutableArray alloc] initWithArray:extensions];

    self.running = NO;
}

-(void)downloadFileAtURL:(NSURL *)url {

    NSString *fileExtension = [url pathExtension];

    if ([self.supportedFormats containsObject:fileExtension]) {

        self.downloadAgent = [[NSURLConnection alloc] initWithRequest:[NSURLRequest requestWithURL:url] delegate:self];

        [self.downloadAgent start];

        NSLog(@"Beginning download at URL:%@", url.absoluteString);

    }
    else {

    }

}

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

    NSLog(@"Connection recieved response with size: %f", (float)[response expectedContentLength]);

    self.expectedContentSize = (float)[response expectedContentLength];

    self.running = YES;

    NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse*)response;

    NSLog(@"%i", [httpResponse statusCode]);

    /*

    if ([httpResponse statusCode] >= 200 && [httpResponse statusCode] <= 299) {

    }

     */

}

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

    NSLog(@"%f", (float)[data length]);

    [currentData appendData:data];

    self.currentDownloadProgress = ((float)[data length] / self.currentDownloadProgress);

    NSLog(@"Connection recieved data. New progress is: %f", self.currentDownloadProgress);

    if ([self.delegate respondsToSelector:@selector(downloader:progressChanged:)]) {
        [self.delegate downloader:self progressChanged:self.currentDownloadProgress];
    }

}

-(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {

    NSLog(@"Connection failed");

    if ([self.delegate respondsToSelector:@selector(downloader:failedToDownloadFileAtURL:reason:)]) {
        [self.delegate downloader:self failedToDownloadFileAtURL:connection.originalRequest.URL reason:error];
    }

}

-(void)connectionDidFinishDownloading:(NSURLConnection *)connection destinationURL:(NSURL *)destinationURL {

    NSLog(@"Connection finished downloading with size: %f", (float)[currentData length]);

    self.running = NO;

    NSString *filename = [destinationURL.absoluteString lastPathComponent];

    NSString *docPath = [self documentsDirectoryPath];

    NSString *pathToDownloadTo = [NSString stringWithFormat:@"%@/%@", docPath, filename];

    NSError *error = nil;

    [currentData writeToFile:pathToDownloadTo options:NSDataWritingAtomic error:&error];

    if (error != nil) {

        NSLog(@"DIFileDownloader: Failed to save the file because: %@", [error description]);

        if ([self.delegate respondsToSelector:@selector(downloader:failedToDownloadFileAtURL:reason:)]) {
            [self.delegate downloader:self failedToDownloadFileAtURL:connection.originalRequest.URL reason:error];
        }

} 
    else {

        if ([self.delegate respondsToSelector:@selector(downloader:finishedDownloadingFileNamed:atPath:)]) {
            [self.delegate downloader:self finishedDownloadingFileNamed:filename atPath:pathToDownloadTo];
        }

    }

}

- (NSString *)documentsDirectoryPath {
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *documentsDirectoryPath = [paths objectAtIndex:0];
    return documentsDirectoryPath;
}

@end

person JohnWickham    schedule 14.07.2013    source источник
comment
Ну, во-первых, вы никогда не создаете свой объект NSMutableData.   -  person jscs    schedule 14.07.2013
comment
И тогда похоже, что у вас та же проблема, что и NSURLConnection connection:didReceiveData: is not вызывается на ios5. Также есть еще один полезный ответ на NSURLConnection didReceiveData: не вызывался iOS   -  person jscs    schedule 14.07.2013
comment
В вашем коде есть ряд ошибок: ваш метод инициализации не соответствует правилам и не возвращает объект. То, как вы вычисляете currentDownloadProgress, не работает, и еще несколько. Я бы предложил добавить довольно много утверждений и проверок ошибок в ваш код, а затем начать сеансы отладки.   -  person CouchDeveloper    schedule 14.07.2013


Ответы (1)


Как упоминалось в других и в моем комментарии, в вашем коде есть несколько ошибок, которые вам нужно исправить.

Но есть и одно большое заблуждение, вытекающее из прежней ужасной документации NSURLConnection:

connectionDidFinishDownloading:destinationURL: НЕ является методом делегата двух делегатов NSURLConnection, а именно NSURLConnectionDelegate и NSURLConnectionDataDelegate, которые вы должны реализовать в своем случае.

Минимальный набор методов делегата, которые вам необходимо реализовать:

Для NSURLConnectionDelegate:

  • (void) соединение: (NSURLConnection *) соединение didFailWithError: (NSError *) ошибка;

затем для NSURLConnectionDataDelegate:

  • (void) соединение: (NSURLConnection *) соединение didReceiveResponse: (NSURLResponse *) ответ;

  • (void) соединение: (NSURLConnection *) соединение didReceiveData: (NSData *) данные;

  • (void) соединениеDidFinishLoading: (NSURLConnection*) соединение;

Если вы не возражаете, я разместил образец минимальной реализации в Gist: SimpleGetHTTPRequest. который должен дать вам быстрый старт, реализовать свой собственный класс HTTP-запросов.

person CouchDeveloper    schedule 14.07.2013
comment
Спасибо за этот образец, я думаю, у меня есть то, что мне нужно! - person JohnWickham; 15.07.2013