URLSession 可以設定在背景中下載檔案,但是除了只能使用 URLSessionDownloadTask 外,並且必須設定 delegate 而不能使用 block 來取得檔案路徑。
步驟說明
- 建立 Single View App 專案
- 若為 http 網址,ATS 設定請參考附錄 D。
- 開啟 Main.storyboard,拖放一個 Image View 元件到 View Controller 上。
開啟 ViewController.swift,用藍線設定 Image View 元件的 IBOutlet 屬性,並且讓這個類別符合 URLSessionDownloadDelegate 協定的規範。
class ViewController: UIViewController, URLSessionDownloadDelegate { @IBOutlet weak var imageView: UIImageView!
在 viewDidLoad() 中透過 URLSessionDownloadTask 下載圖片,並且設定可在背景執行。
override func viewDidLoad() { super.viewDidLoad() let url = URL(string: "某圖片的網址") //使用者背景設定建立 session,並且給一個 session 的名字 let config = URLSessionConfiguration.background(withIdentifier: "abc") // delegateQueue 如果為 nil,delegate 會在另外一個執行緒中被呼叫 let session = URLSession(configuration: config, delegate: self,delegateQueue: nil) let dnTask = session.downloadTask(with: url!) dntask.resume() }
如果參數 delegateQueue 填入 OperationQueue.main,則所有的 delegate 都會在主執行緒中執行。
這個函數會在檔案下載完成並且存檔後呼叫。所以我們在這個函數中透過存檔路徑開啟檔案,然後在 Image View 上顯示。
func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL) { if let data = try? Data(contentsOf: location) { DispatchQueue.main.async(execute: { self.imageView.image = UIImage(data: data) }) } }
實作這個函數可以在下載完成後得知是否有錯誤產生
func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) { if error == nil { print("下載成功") }else { print("下載失敗: \(error!)") } }
實作此函數可以當 APP 從背景變成前景時通知使用者下載已經完成。
func urlSessionDidFinishEvents(forBackgroundURLSession session: URLSession) { print("下載程式完成") }
這個函數可以得知目前下載進度,注意只有當 APP 在前景時才會被呼叫。
func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didWriteData byteWritten: Int64, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64) { //計算下載進度 let progress = Float(totalBytesWritten) / Float(totalBytesExpectedToWrite) print("下載進度 \(progress)") }
執行結果
下載進度 0.93537 下載進度 1.0