Alamofire-下載器

1、suspend和resume

  • Requestsuspend
/// 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]
        )
    }
複製代碼
  • Requestresume
/// 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

  • Requestcancel
/// 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]
        )
    }
複製代碼
  • DownloadRequestcancel,重寫了RequestcancelAlamofire幫咱們保存了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("清理完成")
        }
    }
}
複製代碼
相關文章
相關標籤/搜索