ios 快速从 dataTaskWithURL 获取进度

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/30543806/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-31 06:08:10  来源:igfitidea点击:

get progress from dataTaskWithURL in swift

iosswift

提问by taffarel

Is there any way to get progress from dataTaskWithURLin swift while the data is downloading?

有什么方法可以dataTaskWithURL在下载数据时快速获取进度?

NSURLSession.sharedSession().dataTaskWithURL(...)

I need to show progress bar while the data is downloading.

我需要在下载数据时显示进度条。

回答by Dharmesh Kheni

you can use this code for showing download process with progress bar with its delegate functions.

您可以使用此代码显示带有委托功能的进度条的下载过程。

import UIKit

class ViewController: UIViewController,NSURLSessionDelegate,NSURLSessionDataDelegate{

    @IBOutlet weak var progress: UIProgressView!

    var buffer:NSMutableData = NSMutableData()
    var session:NSURLSession?
    var dataTask:NSURLSessionDataTask?
    let url = NSURL(string:"http://i.stack.imgur.com/b8zkg.png" )!
    var expectedContentLength = 0


    override func viewDidLoad() {
        super.viewDidLoad()
        progress.progress = 0.0
        let configuration = NSURLSessionConfiguration.defaultSessionConfiguration()
        let manqueue = NSOperationQueue.mainQueue()
        session = NSURLSession(configuration: configuration, delegate:self, delegateQueue: manqueue)
        dataTask = session?.dataTaskWithRequest(NSURLRequest(URL: url))
        dataTask?.resume()

        // Do any additional setup after loading the view, typically from a nib.
    }
    func URLSession(session: NSURLSession, dataTask: NSURLSessionDataTask, didReceiveResponse response: NSURLResponse, completionHandler: (NSURLSessionResponseDisposition) -> Void) {

        //here you can get full lenth of your content
        expectedContentLength = Int(response.expectedContentLength)
        println(expectedContentLength)
        completionHandler(NSURLSessionResponseDisposition.Allow)
    }
    func URLSession(session: NSURLSession, dataTask: NSURLSessionDataTask, didReceiveData data: NSData) {


        buffer.appendData(data)

        let percentageDownloaded = Float(buffer.length) / Float(expectedContentLength)
        progress.progress =  percentageDownloaded
    }
    func URLSession(session: NSURLSession, task: NSURLSessionTask, didCompleteWithError error: NSError?) {
        //use buffer here.Download is done
        progress.progress = 1.0   // download 100% complete
    }
}

回答by yas375

You can simply observe progressproperty of the URLSessionDataTaskobject.

您可以简单地观察对象的progress属性URLSessionDataTask

Example:

例子:

import UIKit

class SomeViewController: UIViewController {

  private var observation: NSKeyValueObservation?

  deinit {
    observation?.invalidate()
  }

  override func viewDidLoad() {
    super.viewDidLoad()

    let url = URL(string: "https://source.unsplash.com/random/4000x4000")!
    let task = URLSession.shared.dataTask(with: url)

    observation = task.progress.observe(\.fractionCompleted) { progress, _ in
      print("progress: ", progress.fractionCompleted)
    }

    task.resume()
  }
}

Playground example:

游乐场示例:

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()

回答by Vlad

Update for Swift4:
Supports execution of multiple simultaneous operations.

Swift4更新:
支持同时执行多个操作。

File: DownloadService.swift. Keeps reference to URLSession and tracks executing tasks.

文件:DownloadService.swift。保持对 URLSession 的引用并跟踪正在执行的任务。

final class DownloadService: NSObject {

   private var session: URLSession!
   private var downloadTasks = [GenericDownloadTask]()

   public static let shared = DownloadService()

   private override init() {
      super.init()
      let configuration = URLSessionConfiguration.default
      session = URLSession(configuration: configuration,
                           delegate: self, delegateQueue: nil)
   }

   func download(request: URLRequest) -> DownloadTask {
      let task = session.dataTask(with: request)
      let downloadTask = GenericDownloadTask(task: task)
      downloadTasks.append(downloadTask)
      return downloadTask
   }
}


extension DownloadService: URLSessionDataDelegate {

   func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive response: URLResponse,
                   completionHandler: @escaping (URLSession.ResponseDisposition) -> Void) {

      guard let task = downloadTasks.first(where: { 
protocol DownloadTask {

   var completionHandler: ResultType<Data>.Completion? { get set }
   var progressHandler: ((Double) -> Void)? { get set }

   func resume()
   func suspend()
   func cancel()
}
.task == dataTask }) else { completionHandler(.cancel) return } task.expectedContentLength = response.expectedContentLength completionHandler(.allow) } func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive data: Data) { guard let task = downloadTasks.first(where: {
class GenericDownloadTask {

   var completionHandler: ResultType<Data>.Completion?
   var progressHandler: ((Double) -> Void)?

   private(set) var task: URLSessionDataTask
   var expectedContentLength: Int64 = 0
   var buffer = Data()

   init(task: URLSessionDataTask) {
      self.task = task
   }

   deinit {
      print("Deinit: \(task.originalRequest?.url?.absoluteString ?? "")")
   }

}

extension GenericDownloadTask: DownloadTask {

   func resume() {
      task.resume()
   }

   func suspend() {
      task.suspend()
   }

   func cancel() {
      task.cancel()
   }
}
.task == dataTask }) else { return } task.buffer.append(data) let percentageDownloaded = Double(task.buffer.count) / Double(task.expectedContentLength) DispatchQueue.main.async { task.progressHandler?(percentageDownloaded) } } func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) { guard let index = downloadTasks.index(where: {
public enum ResultType<T> {

   public typealias Completion = (ResultType<T>) -> Void

   case success(T)
   case failure(Swift.Error)

}
.task == task }) else { return } let task = downloadTasks.remove(at: index) DispatchQueue.main.async { if let e = error { task.completionHandler?(.failure(e)) } else { task.completionHandler?(.success(task.buffer)) } } } }

File: DownloadTask.swift. Lightweight interface just to hide concrete implementation.

文件:DownloadTask.swift。轻量级接口只是为了隐藏具体的实现。

class ViewController: NSViewController {

   @IBOutlet fileprivate weak var loadImageButton1: NSButton!
   @IBOutlet fileprivate weak var loadProgressIndicator1: NSProgressIndicator!
   @IBOutlet fileprivate weak var imageView1: NSImageView!

   @IBOutlet fileprivate weak var loadImageButton2: NSButton!
   @IBOutlet fileprivate weak var loadProgressIndicator2: NSProgressIndicator!
   @IBOutlet fileprivate weak var imageView2: NSImageView!

   fileprivate var downloadTask1:  DownloadTask?
   fileprivate var downloadTask2:  DownloadTask?

   override func viewDidLoad() {
      super.viewDidLoad()
      loadImageButton1.target = self
      loadImageButton1.action = #selector(startDownload1(_:))
      loadImageButton2.target = self
      loadImageButton2.action = #selector(startDownload2(_:))
   }

}


extension ViewController {

   @objc fileprivate func startDownload1(_ button: NSButton) {
      let url = URL(string: "http://localhost:8001/?imageID=01&tilestamp=\(Date.timeIntervalSinceReferenceDate)")!
      let request = URLRequest(url: url, cachePolicy: .reloadIgnoringLocalCacheData, timeoutInterval: 30)
      downloadTask1 = DownloadService.shared.download(request: request)
      downloadTask1?.completionHandler = { [weak self] in
         switch 
#!/bin/bash

AWLScriptDirPath=$(cd "$(dirname "
<?php

$imageID = $_REQUEST["imageID"];
$local_file = "Image-$imageID.jpg";

$download_rate = 20.5; // set the download rate limit (=> 20,5 kb/s)
if (file_exists($local_file) && is_file($local_file)) {
    header('Cache-control: private');
    header('Content-Type: image/jpeg');
    header('Content-Length: '.filesize($local_file));

    flush();
    $file = fopen($local_file, "r");
    while(!feof($file)) {
        // send the current file part to the browser
        print fread($file, round($download_rate * 1024));
        flush(); // flush the content to the browser
        usleep(0.25 * 1000000);
    }
    fclose($file);}
else {
    die('Error: The file '.$local_file.' does not exist!');
}

?>
")"; pwd) cd "$AWLScriptDirPath" php -S localhost:8001 & php -S localhost:8002 & ps -afx | grep php echo "Press ENTER to exit." read killall php
{ case .failure(let error): print(error) case .success(let data): print("Number of bytes: \(data.count)") self?.imageView1.image = NSImage(data: data) } self?.downloadTask1 = nil self?.loadImageButton1.isEnabled = true } downloadTask1?.progressHandler = { [weak self] in print("Task1: \(
Image-01.jpg
Image-02.jpg
StartPHPWebServer.command
index.php
)") self?.loadProgressIndicator1.doubleValue =
class AudioPlayerViewController: UIViewController, URLSessionDelegate, URLSessionDataDelegate, URLSessionDownloadDelegate{


         var defaultSession: URLSession!
         var downloadTask: URLSessionDownloadTask!
} loadImageButton1.isEnabled = false imageView1.image = nil loadProgressIndicator1.doubleValue = 0 downloadTask1?.resume() } @objc fileprivate func startDownload2(_ button: NSButton) { let url = URL(string: "http://localhost:8002/?imageID=02&tilestamp=\(Date.timeIntervalSinceReferenceDate)")! let request = URLRequest(url: url, cachePolicy: .reloadIgnoringLocalCacheData, timeoutInterval: 30) downloadTask2 = DownloadService.shared.download(request: request) downloadTask2?.completionHandler = { [weak self] in switch
            defaultSession = Foundation.URLSession(configuration: .default, delegate: self, delegateQueue: nil)
            downloadProgress.setProgress(0.0, animated: false)
            downloadTask = defaultSession.downloadTask(with: audioUrl)
            downloadTask.Resume()
{ case .failure(let error): print(error) case .success(let data): print("Number of bytes: \(data.count)") self?.imageView2.image = NSImage(data: data) } self?.downloadTask2 = nil self?.loadImageButton2.isEnabled = true } downloadTask2?.progressHandler = { [weak self] in print("Task2: \(
func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didWriteData bytesWritten: Int64, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64) {

    DispatchQueue.main.async {
        self.downloadProgressBar.setProgress(Float(totalBytesWritten)/Float(totalBytesExpectedToWrite), animated: true)
    }
}

func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL) {
        DispatchQueue.main.async {

//DOWNLOAD SUCCESSFUL AND FILE PATH WILL BE IN URL.

}
}
)") self?.loadProgressIndicator2.doubleValue =
import UIKit

class ViewController: UIViewController, URLSessionDelegate, URLSessionDataDelegate {
    // MARK: - Variables

    // MARK: - IBOutlet
    @IBOutlet weak var progress: UIProgressView!

    // MARK: - IBAction
    @IBAction func goTapped(_ sender: UIButton) {
        let url = URL(string: "http://www.example.com/file.zip")!
        fetchFile(url: url)
    }

    // MARK: - Life cycle
    override func viewDidLoad() {
        super.viewDidLoad()
    }

    func fetchFile(url: URL) {
        progress.progress = 0.0
        let configuration = URLSessionConfiguration.default
        let mainQueue = OperationQueue.main
        session = URLSession(configuration: configuration, delegate: self, delegateQueue: mainQueue)
        dataTask = session?.dataTask(with: URLRequest(url: url))
        dataTask?.resume()
    }

    var buffer: NSMutableData = NSMutableData()
    var session: URLSession?
    var dataTask: URLSessionDataTask?
    var expectedContentLength = 0

    func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive data: Data) {
        buffer.append(data)
        let percentageDownloaded = Float(buffer.length) / Float(expectedContentLength)
        progress.progress =  percentageDownloaded
    }

    func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive response: URLResponse, completionHandler: (URLSession.ResponseDisposition) -> Void) {
        expectedContentLength = Int(response.expectedContentLength)
        completionHandler(URLSession.ResponseDisposition.allow)
    }

    func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) {
        progress.progress = 1.0
    }
}
} loadImageButton2.isEnabled = false imageView2.image = nil loadProgressIndicator2.doubleValue = 0 downloadTask2?.resume() } }

File: GenericDownloadTask.swift. Concrete implementation of DownloadTaskinterface.

文件:GenericDownloadTask.swiftDownloadTask接口的具体实现。

##代码##

File: ResultType.swift. Reusable type to keep result or error.

文件:ResultType.swift。可重用类型以保留结果或错误。

##代码##

Usage: Example how to run two download tasks in parallel(macOS App):

用法:示例如何运行two download tasks in parallel(macOS App):

##代码##

Bonus 1. File StartPHPWebServer.command. Example script to run 2 Build-in PHP servers to simulate simultaneous downloads.

奖金 1。文件StartPHPWebServer.command. 运行 2 个内置 PHP 服务器以模拟同时下载的示例脚本。

##代码##

Bonus 2. File index.php. Example PHP script to implement slow download.

奖金 2。文件index.php. 示例 PHP 脚本来实现慢速下载。

##代码##

Misc: Contents of directory which simulates 2 PHP servers.

其他:模拟 2 个 PHP 服务器的目录内容。

##代码##

回答by Krishna Kirana

in class declare

在课堂上声明

##代码##

in download method

在下载方法中

##代码##

And add following delegates:

并添加以下代表:

##代码##

回答by El Tomato

In reference to Dharmesh's work, there have been quite a number of minor changes with URLSessionDelegateand URLSessionDataDelegatedelegate methods. Here come the code for Swift 4.2compatibility.

参考 Dharmesh 的工作,对URLSessionDelegateURLSessionDataDelegate委托方法进行了相当多的小改动。这是Swift 4.2兼容性的代码。

##代码##

回答by Icaro

for the data been download you need to set the NSURLSessionDownloadDelegateand to implement URLSession(_:downloadTask:didWriteData:totalBytesWritten:totalBytesExpectedToWrite:)

对于已下载的数据,您需要设置NSURLSessionDownloadDelegate并实现URLSession(_:downloadTask:didWriteData:totalBytesWritten:totalBytesExpectedToWrite:)

There is a nice tutorial about it herebut is in object-c.

有一个关于它一个很好的教程在这里,但是在对象的C。