问题描述
我正在尝试在 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)
}
}
}
我希望代码足够自我记录。