一、suspend和resume
/// Suspends the request.
open func suspend() {
guard let task = task else { return }
task.suspend()
NotificationCenter.default.post(
name: Notification.Name.Task.DidSuspend,
object: self,
userInfo: [Notification.Key.Task: task]
)
}
/// Resumes the request.
open func resume() {
guard let task = task else { delegate.queue.isSuspended = false ; return }
if startTime == nil { startTime = CFAbsoluteTimeGetCurrent() }
task.resume()
NotificationCenter.default.post(
name: Notification.Name.Task.DidResume,
object: self,
userInfo: [Notification.Key.Task: task]
)
}
- 总结
resume
之后可以suspend
,suspend
之后也可以resume
currentDownloadRequest = LGDowloadManager.shared.manager.download(url) { [weak self](url, reponse) -> (destinationURL: URL, options: DownloadRequest.DownloadOptions) in
let fileUrl = self?.filePath.appendingPathComponent(reponse.suggestedFilename!)
return (fileUrl!,[.removePreviousFile, .createIntermediateDirectories] )
}
二、cancel
/// Cancels the request.
open func cancel() {
guard let task = task else { return }
task.cancel()
NotificationCenter.default.post(
name: Notification.Name.Task.DidCancel,
object: self,
userInfo: [Notification.Key.Task: task]
)
}
-
DownloadRequest
的cancel
,重写了Request
的cancel
,Alamofire
帮我们保存了self.downloadDelegate.resumeData
/// Cancels the request.
open override func cancel() {
downloadDelegate.downloadTask.cancel { self.downloadDelegate.resumeData = $0 }
NotificationCenter.default.post(
name: Notification.Name.Task.DidCancel,
object: self,
userInfo: [Notification.Key.Task: task as Any]
)
}
- 总结
Alamofire
帮我们保存了resumeData
,直接取出来用,避免了在沙盒中找到然后在后面拼接,resumeData
中包含了这些信息哦
- 优化代码二
if let resumeData = LGDowloadManager.shared.currentDownloadRequest?.resumeData {
currentDownloadRequest = LGDowloadManager.shared.manager.download(resumingWith: resumeData)
}else{
currentDownloadRequest = LGDowloadManager.shared.manager.download(url) { [weak self](url, reponse) -> (destinationURL: URL, options: DownloadRequest.DownloadOptions) in
let fileUrl = self?.filePath.appendingPathComponent(reponse.suggestedFilename!)
return (fileUrl!,[.removePreviousFile, .createIntermediateDirectories] )
}
}
三、用户杀死应用程序
- 用户杀死应用程序,会导致下载暂停,再次启动程序会来到
urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?)
extension SessionDelegate: URLSessionTaskDelegate {
// 省略...
open func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) {
/// Executed after it is determined that the request is not going to be retried
let completeTask: (URLSession, URLSessionTask, Error?) -> Void = { [weak self] session, task, error in
guard let strongSelf = self else { return }
strongSelf.taskDidComplete?(session, task, error)
// 省略...
}
}
}
-
Alamofire
对外闭包的使用,对外实现taskDidComplete
闭包,就可以监控到啦
- 取出error中的
NSURLSessionDownloadTaskResumeData
,赋值给LGDowloadManager.shared.resumeData
- 优化代码三
manager.delegate.taskDidComplete = { (seesion,task, error) in
if let error = error {
print("taskDidComplete的error情况: \(error)")
if let resumeData = (error as NSError).userInfo[NSURLSessionDownloadTaskResumeData] as? Data {
// resumeData 存储
LGDowloadManager.shared.resumeData = resumeData
print("来了")
}
}else{
print("taskDidComplete的task情况: \(task)")
}
}
if self.resumeData != nil {
currentDownloadRequest = LGDowloadManager.shared.manager.download(resumingWith: self.resumeData!)
}else{
if let resumeData = LGDowloadManager.shared.currentDownloadRequest?.resumeData {
currentDownloadRequest = LGDowloadManager.shared.manager.download(resumingWith: resumeData)
}else{
currentDownloadRequest = LGDowloadManager.shared.manager.download(url) { [weak self](url, reponse) -> (destinationURL: URL, options: DownloadRequest.DownloadOptions) in
let fileUrl = self?.filePath.appendingPathComponent(reponse.suggestedFilename!)
return (fileUrl!,[.removePreviousFile, .createIntermediateDirectories] )
}
}
}
四、代码崩溃导致kill程序
- 后台其实还是在继续下载的
- 进度返回 实现闭包
downloadTaskDidWriteData
- 不能再继续点击开始
manager.session.getTasksWithCompletionHandler({ (dataTasks, uploadTask, downloadTasks) in
print("回调监控: \(downloadTasks)")
})
manager.delegate.downloadTaskDidFinishDownloadingToURL = { (session, downloadTask, url) in
guard let response = downloadTask.response as? HTTPURLResponse else {return}
let fileUrl = LGDowloadManager.shared.filePath.appendingPathComponent(response.suggestedFilename!)
do {
if FileManager.default.fileExists(atPath: fileUrl.path) {
try FileManager.default.removeItem(at: fileUrl)
}
let directory = fileUrl.deletingLastPathComponent()
try FileManager.default.createDirectory(at: directory, withIntermediateDirectories: true)
try FileManager.default.moveItem(at: url, to: fileUrl)
print("文件移动成功")
} catch {
print("文件移动出错了 \(error)")
}
}
五、代码实例
import UIKit
import Alamofire
class LGDowloadManager: NSObject {
static let shared = LGDowloadManager()
var currentDownloadRequest: DownloadRequest?
var resumeData: Data?
var downloadTasks: Array<URLSessionDownloadTask>?
var filePath: URL{
return FileManager.default.urls(for: .documentDirectory, in: FileManager.SearchPathDomainMask.userDomainMask).first!.appendingPathComponent("com.lgcooci.download.cn")
}
//MARK: - 单利方便获取
let manager: SessionManager = {
let configuration = URLSessionConfiguration.background(withIdentifier: "com.lgcooci.AlamofireDowload")
configuration.httpAdditionalHeaders = SessionManager.defaultHTTPHeaders
configuration.sharedContainerIdentifier = "group.com.lgcooci.AlamofireDowload"
let manager = SessionManager(configuration: configuration)
manager.startRequestsImmediately = true
manager.backgroundCompletionHandler = {
debugPrint("后台完成回来了")
}
// 用户kill 进来
manager.delegate.taskDidComplete = { (seesion,task, error) in
if let error = error {
print("taskDidComplete的error情况: \(error)")
if let resumeData = (error as NSError).userInfo[NSURLSessionDownloadTaskResumeData] as? Data {
// resumeData 存储
LGDowloadManager.shared.resumeData = resumeData
print("来了")
}
}else{
print("taskDidComplete的task情况: \(task)")
}
}
manager.session.getTasksWithCompletionHandler({ (dataTasks, uploadTask, downloadTasks) in
print("回调监控: \(downloadTasks)")
})
manager.delegate.downloadTaskDidFinishDownloadingToURL = { (session, downloadTask, url) in
guard let response = downloadTask.response as? HTTPURLResponse else {return}
let fileUrl = LGDowloadManager.shared.filePath.appendingPathComponent(response.suggestedFilename!)
do {
if FileManager.default.fileExists(atPath: fileUrl.path) {
try FileManager.default.removeItem(at: fileUrl)
}
let directory = fileUrl.deletingLastPathComponent()
try FileManager.default.createDirectory(at: directory, withIntermediateDirectories: true)
try FileManager.default.moveItem(at: url, to: fileUrl)
print("文件移动成功")
} catch {
print("文件移动出错了 \(error)")
}
}
return manager
}()
//MARK: - 下载封装入口 - 断点续传
func lgDowload(_ url: URLConvertible) -> DownloadRequest {
if self.resumeData != nil {
currentDownloadRequest = LGDowloadManager.shared.manager.download(resumingWith: self.resumeData!)
}else{
if let resumeData = LGDowloadManager.shared.currentDownloadRequest?.resumeData {
currentDownloadRequest = LGDowloadManager.shared.manager.download(resumingWith: resumeData)
}else{
currentDownloadRequest = LGDowloadManager.shared.manager.download(url) { [weak self](url, reponse) -> (destinationURL: URL, options: DownloadRequest.DownloadOptions) in
let fileUrl = self?.filePath.appendingPathComponent(reponse.suggestedFilename!)
return (fileUrl!,[.removePreviousFile, .createIntermediateDirectories] )
}
}
}
return currentDownloadRequest!
}
//MARK: - 暂停/继续/取消
func suspend() {
self.currentDownloadRequest?.suspend()
}
func resume() {
self.currentDownloadRequest?.resume()
}
func cancel() {
self.currentDownloadRequest?.cancel()
}
func clear() {
let filePath = NSHomeDirectory()+"/Documents/com.lgcooci.download.cn"
if FileManager.default.fileExists(atPath: filePath) {
try! FileManager.default.removeItem(at: self.filePath)
print("清理完成")
}
}
}
网友评论