Подтвердить что ты не робот

Отображение прогресса загрузки файла с помощью NSURLSessionDataTask

Я хочу показать ход загрузки файла (сколько байтов получено) определенного файла. Он отлично работает с NSURLSessionDownloadTask. Мой вопрос: я хочу достичь того же с помощью NSURLSessionDataTask.

Вот код, который получает файл в NSData и записывает в папку документа:

NSURLSessionConfiguration *defaultConfigObject = [NSURLSessionConfiguration defaultSessionConfiguration];

NSURLSession *defaultSession = [NSURLSession sessionWithConfiguration: defaultConfigObject delegate: self delegateQueue: [NSOperationQueue mainQueue]];

NSURLSessionDataTask * dataTask = [defaultSession dataTaskWithURL:theRessourcesURL
    completionHandler:^(NSData *data, NSURLResponse *response, NSError *error)
{ 
       if(error == nil)
       {

            NSString *docsDir = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];

               NSString *pathToDownloadTo = [NSString stringWithFormat:@"%@/%@", docsDir, Name];

               NSLog(@"SIZE : %@",[NSByteCountFormatter stringFromByteCount:data.length countStyle:NSByteCountFormatterCountStyleFile]);

               [data writeToFile:pathToDownloadTo options:NSDataWritingAtomic error:&error];
       }
}];

[dataTask resume];

Я получаю размер файла после записи или полной datatask (после получения файла):

NSLog(@"SIZE : %@",[NSByteCountFormatter stringFromByteCount:data.length countStyle:NSByteCountFormatterCountStyleFile]);

Но я хочу отобразить текущий статус полученных байтов, возможно ли это с помощью NSURLSessionDataTask?

4b9b3361

Ответ 1

Вам необходимо реализовать следующие делегаты:

<NSURLSessionDataDelegate, NSURLSessionDelegate, NSURLSessionTaskDelegate>

Также необходимо создать два свойства:

@property (nonatomic, retain) NSMutableData *dataToDownload;
@property (nonatomic) float downloadSize;

- (void)viewDidLoad {
    [super viewDidLoad];

    NSURLSessionConfiguration *defaultConfigObject = [NSURLSessionConfiguration defaultSessionConfiguration];

    NSURLSession *defaultSession = [NSURLSession sessionWithConfiguration: defaultConfigObject delegate: self delegateQueue: [NSOperationQueue mainQueue]];

    NSURL *url = [NSURL URLWithString: @"your url"];
    NSURLSessionDataTask *dataTask = [defaultSession dataTaskWithURL: url];

    [dataTask resume];
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveResponse:(NSURLResponse *)response completionHandler:(void (^)(NSURLSessionResponseDisposition disposition))completionHandler {
    completionHandler(NSURLSessionResponseAllow);

    progressBar.progress=0.0f;
    _downloadSize=[response expectedContentLength];
    _dataToDownload=[[NSMutableData alloc]init];
}

- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data {
    [_dataToDownload appendData:data];
    progressBar.progress=[ _dataToDownload length ]/_downloadSize;
}

Ответ 2

Вы также можете использовать NSURLSessionDownloadTask, как показано ниже. Вызов startDownload methode.In.h используйте этот

- (void)startDownload
{
    NSString *s;
    s = @"http://www.nasa.gov/sites/default/files/styles/1600x1200_autoletterbox/public/pia17474_1.jpg?itok=4fyEwd02";
    NSURLSessionDownloadTask *task = [self.session downloadTaskWithURL:[NSURL URLWithString:s]];
    [task resume];
}

- (NSURLSession *) configureSession {
    NSURLSessionConfiguration *config =
    [NSURLSessionConfiguration backgroundSessionConfiguration:@"com.neuburg.matt.ch37backgroundDownload"];
    config.allowsCellularAccess = NO;
    // ... could set config.discretionary here ...
    NSURLSession *session = [NSURLSession sessionWithConfiguration:config delegate:self delegateQueue:[NSOperationQueue mainQueue]];
    return session;
}

-(void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite {
    CGFloat prog = (float)totalBytesWritten/totalBytesExpectedToWrite;
    NSLog(@"downloaded %d%%", (int)(100.0*prog));

}

-(void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didResumeAtOffset:(int64_t)fileOffset expectedTotalBytes:(int64_t)expectedTotalBytes {
    // unused in this example
}

-(void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location {
    NSData *d = [NSData dataWithContentsOfURL:location];
    UIImage *im = [UIImage imageWithData:d];
    dispatch_async(dispatch_get_main_queue(), ^{
        self.image = im;

    });
}

-(void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error {
    NSLog(@"completed; error: %@", error);
}

Ответ 3

Поскольку iOS 11.0 и macOS 10.13, URLSessionTask (бывший NSURLSessionTask) принял протокол ProgressReporting. Это означает, что вы можете использовать свойство progress для отслеживания хода выполнения задачи сеанса.

Ожидая, что вы уже знаете, как использовать наблюдателей KVO, вы можете сделать что-то вроде:

task = session.downloadTask(with: url)
task.resume()
task.progress.addObserver(self, forKeyPath: "fractionCompleted", options: .new, context: &self.progressKVOContext)

и соблюдайте значение с помощью:

override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
    if context == &self.progressKVOContext, let keyPath = keyPath {
        switch keyPath {
        case "fractionCompleted":
            guard let progress = object as? Progress else {
                return
            }
            DispatchQueue.main.async { [weak self] in
                self?.onDownloadProgress?(progress.fractionCompleted)
            }
        case "isCancelled":
            cancel()
        default:
            break
        }
    }
    else {
        super.observeValue(forKeyPath: keyPath, of: object, change: change, context: context)
    }
}

Обновление iOS 13

OperationQueue теперь имеет свойство progress.

Например, UIProgressView может наблюдать это свойство и автоматически обновлять значение прогресса, используя observedProgress. Полный пример в https://nshipster.com/ios-13/#track-the-progress-of-enqueued-operations.

Ответ 4

import Foundation
import PlaygroundSupport

let page = PlaygroundPage.current
page.needsIndefiniteExecution = true

let url = URL(string: "https://source.unsplash.com/random/4000x4000")!
let task = URLSession.shared.dataTask(with: url) { _, _, _ in
  page.finishExecution()
}

// Don't forget to invalidate the observation when you don't need it anymore.
let observation = task.progress.observe(\.fractionCompleted) { progress, _ in
  print(progress.fractionCompleted)
}

task.resume()