如何在没有 NSURLSession 的情况下在 Swift 中下载 .zip 文件?

问题描述

我正在尝试在 iOS 应用中将 zip 文件下载到用户的手机存储中。没有 NSURLSession 是否可以做到这一点?

解决方法

是的,有多种工具,但您仍然应该尝试使用 URL 会话。

一个非常简单的方法是使用 Data。但它会阻塞您的线程,因此您需要对队列进行一些处理才能使其正常工作(否则您的应用可能会崩溃)。

一种非常简单、不安全、线程阻塞的方法是:

func saveFile(atRemoteURL remoteURL: URL,to localURL: URL) {
    let data = try! Data(contentsOf: remoteURL)
    try! data.write(to: localURL)
}

但是做的更稳定一点应该是这样的:

private func downloadIteam(atURL url: URL,completion: ((_ data: Data?,_ error: Error?) -> Void)?) {
    let queue = DispatchQueue(label: "downloading_file")
    queue.async {
        do {
            let data = try Data(contentsOf: url)
            completion?(data,nil)
        } catch {
            completion?(nil,error)
        }
    }
}

private func saveDataToDocuments(_ data: Data,to: String,completion: ((_ resultPath: URL?,_ error: Error?) -> Void)?) {
    let path = FileManager.default.urls(for: .documentDirectory,in: .userDomainMask)[0].appendingPathComponent(to)
    let queue = DispatchQueue(label: "saving_file")
    queue.async {
        do {
            let folderPath: String = path.deletingLastPathComponent().path
            if !FileManager.default.fileExists(atPath: folderPath) {
                try FileManager.default.createDirectory(atPath: folderPath,withIntermediateDirectories: true,attributes: nil)
            }
            try data.write(to: path)
            completion?(path,error)
        }
    }
}

public func downloadFileAndSaveItToDocuments(urlToRemoteFile: URL,completion: @escaping (_ file: (relativePath: String,fullPath: URL)?,_ error: Error?) -> Void) {
    
    let fileName = urlToRemoteFile.lastPathComponent
    let relativePath = "downloads/" + fileName
    
    func finish(fullPath: URL?,error: Error?) {
        DispatchQueue.main.async {
            if let path = fullPath {
                completion((relativePath,path),error)
            } else {
                completion(nil,error)
            }
        }
    }
    
    downloadIteam(atURL: urlToRemoteFile) { (data,error) in
        guard let data = data else {
            completion(nil,error)
            return
        }
        saveDataToDocuments(data,to: relativePath) { (url,saveError) in
            finish(fullPath: url,error: saveError ?? error)
        }
    }
}

我希望代码足够自我记录。

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...