【问题标题】:Swift: How to catch disk full error on background URLSession.downloadTask?Swift:如何在后台 URLSession.downloadTask 上捕获磁盘已满错误?
【发布时间】:2019-08-13 17:24:42
【问题描述】:

我很难理解我认为什么是容易的。

我有一个 URLSession.downloadTask。我已将下载对象设置为 URLSession 委托,并且以下委托方法确实接收调用,所以我知道我的委托设置正确。

func urlSession(_ session: URLSession, didBecomeInvalidWithError error: Error?)
func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?)
func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL)

我无法捕获的情况是 downloadTask 填满了 iPad 上的磁盘空间。这些委托方法都不会被调用。

我应该如何发现这个错误?

这是我的下载对象:

import Foundation
import Zip
import SwiftyUserDefaults

extension DownloadArchiveTask: URLSessionDownloadDelegate {

    // Updates progress info
    func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask,
                    didWriteData bytesWritten: Int64, totalBytesWritten: Int64,
                    totalBytesExpectedToWrite: Int64) {


        let progress = Float(totalBytesWritten) / Float(totalBytesExpectedToWrite)
        self.delegate?.updateProgress(param: progress)
    }

    // Stores downloaded file
    func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL) {

        print("DownloadArchiveTask: In didFinishDownloadingTo")

    }
}

extension DownloadArchiveTask: URLSessionTaskDelegate {

    func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) {
        print("DownloadArchiveTask: In didCompleteWithError")
        if error != nil {
            print("DownloadArchiveTask: has error")
            self.delegate?.hasDiskSpaceIssue()
        }
    }
}

extension DownloadArchiveTask: URLSessionDelegate {
    // Background task handling
    func urlSessionDidFinishEvents(forBackgroundURLSession session: URLSession) {
        print("DownloadArchiveTask: In handler for downloading archive")
        DispatchQueue.main.async {
            let sessionIdentifier = session.configuration.identifier
            if let sessionId = sessionIdentifier, let app = UIApplication.shared.delegate as? AppDelegate, let handler = app.completionHandlers.removeValue(forKey: sessionId) {
                handler()
            }
        }
    }
    func urlSession(_ session: URLSession, didBecomeInvalidWithError error: Error?) {
        print("DownloadArchiveTask: didBecomeInvalidWithError")
        if error != nil {
            print("DownloadArchiveTask: has error")
            self.delegate?.hasDiskSpaceIssue()
        }
    }
}

class DownloadArchiveTask: NSObject {
    var delegate: UIProgressDelegate?
    var archiveUrl:String = "http://someurl.com/archive.zip"

    var task: URLSessionDownloadTask?

    static var shared = DownloadArchiveTask()

    // Create downloadsSession here, to set self as delegate
    lazy var session: URLSession = {
        let configuration = URLSessionConfiguration.background(withIdentifier: "\(Bundle.main.bundleIdentifier!).background_archive")
        return URLSession(configuration: configuration, delegate: self, delegateQueue: nil)
    }()

    func initialDownload() {
        // Create URL to the source file you want to download
        let fileURL = URL(string: archiveUrl)

        let request = URLRequest(url:fileURL!)

        self.task = self.session.downloadTask(with: request)
        task?.resume()

    }
}

以前有人做过吗?我不敢相信这很难——我一定是以错误的方式解决问题......

【问题讨论】:

  • 如果这是一个问题,也许你可以在下载之前检查磁盘空间,或者你应该使用数据任务而不是下载任务,这样你就可以在下载过程中检查磁盘空间.然后,您当然必须自己保存数据(空间允许)。不过,这听起来一定是一个异常大的下载,所以也许您应该解释一下您要做什么。
  • 我认为你永远不会遇到这个问题,因为苹果管理内存很好,苹果会删除临时文件然后缓存文件。
  • 我会检查数据任务。下载是一个压缩文件,其中包含应用程序的初始图像内容。随着内容随着时间的推移而增长,初始 zip 文件的大小也会随之增长。我们遇到过无法下载 zip 文件的情况。我想要做的是抓住这种情况并将应用程序转换为备份“在线”模式。它适用于网络连接非常差的医院,因此首选的解决方案是将所有图像资产下载并存储在设备上。

标签: ios swift nsurlsessiondownloadtask urlsession


【解决方案1】:

不久前,我不得不为我的公司解决这个问题。现在我的解决方案在 Objective C 中,所以你必须将它转换为 Swift,这应该不难。我创建了一个方法来获取设备上剩余的可用存储空间,然后根据我们正在下载的文件的大小检查它。我的解决方案假设您知道下载文件的大小,在您的情况下,您可以在didWriteData 方法中使用totalBytesExpectedToWrite 参数。

这就是我所做的:

+ (unsigned long long)availableStorage
{
     unsigned long long totalFreeSpace = 0;
     NSError* error = nil;

     NSArray* paths = NSSearchPathForDirectoriesInDomain(NSDocumentDirectory, NSUserDomainMask, YES);
     NSDictionary* dictionary = [[NSFileManager defaultManager] attributesOfFileSystemForPath:[paths lastObject] error:&error];
     if (dictionary)
     {
          NSNumber* freeFileSystemSizeInBytes = [dictionary objectForKey:NSFileSystemFreeSize];
          totalFreeSpace = [freeFileSystemSizeInBytes unsignedLongLongValue];
     }
     return totalFreeSpace;
}

请确保为这些数字留出一些错误空间,因为 iTunes、设备上的设置应用程序与此数字永远不会匹配。我们在这里得到的数字是三个中最小的一个,以 MB 为单位。我希望这会有所帮助,如果您需要将其转换为 Swift 的帮助,请告诉我。

【讨论】:

  • 谢谢,这是我的想法之一 - 在 didWriteData 委托方法中向文件系统询问设备上剩余的可用空间量。似乎它可能会给文件系统带来冲击,所以我决定暂时不去探索它。可能会返回并配置文件
  • 您始终可以使用 bool 值并将其默认设置为 false,当它在 didWriteData 方法中第一次检查时将其切换为 true,而不必再次检查它的其余部分下载并在下载完成后将其切换回 false。
  • 谢谢,我想我会使用totalBytesExpectedToWrite 并在第一个didWriteData 检查可用磁盘空间。我一直在想我必须等待磁盘已满错误,但也许更好的选择是跳过下载,如果它不适合并做其他事情。如果需要,我可以通过此方法取消 downloadTask
  • 是的,这是一个有趣的情况,作为开发人员,您无法控制用户下载到他们设备上的数量,但您必须处理如果他们这样做会发生什么。除了停止下载并告诉用户清除一些空间之外,您无能为力。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-04-06
  • 2010-10-06
  • 2011-09-29
  • 1970-01-01
  • 1970-01-01
  • 2019-11-18
  • 2010-11-06
相关资源
最近更新 更多