1、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] )
}
複製代碼
2、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] )
}
}
複製代碼
3、用戶殺死應用程序
- 用戶殺死應用程序,會致使下載暫停,再次啓動程序會來到
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] )
}
}
}
複製代碼
4、代碼崩潰致使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)")
}
}
複製代碼
5、代碼實例
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("清理完成")
}
}
}
複製代碼