当应用程序在后台并使用UrlSessionDownloadTask下载多个文件时,iOS App崩溃

问题描述

我正在使用一个iOS应用程序,该应用程序需要从服务器下载多个文件(主要是图像)并将其存储在Document Directory中。 我正在将UrlSessionDownloadTask与后台URLSession一起使用Urls下载文件。 当应用程序处于前台时,它工作正常,但是如果我转到后台,又回到前台,则应用程序冻结并在一段时间后崩溃。我尝试了很多事情,但没有任何效果

func downloadAllImages(retryCount: Int = 0,completion: @escaping((Bool)->Void)){
        
        var success: Bool = true
        var count = 0
        print("Image Downloading Start")
        //SVProgressHUD.setStatus("Downloading Images...")
        //CommonClass.showBanner(message: "Image Downloading Start")
        
        for (localName,severPath) in images {
            if DataManager.isInternetAvailable(){
                self.dispatchGroup.enter()
                self.dispatchGroupEnterCount += 1
                let path = severPath
                count += 1
                self.DownloadFile(urlPath: path,localName: localName,itemCount: count)
            }else {
                success = false
                CommonClass.showBanner(message: "No Internet")
            }
        }
        dispatchGroup.notify(queue: .main) {
            //retry If some Images Failed to download
            completion(success)
        
        }
    }
    
    
    func DownloadFile(urlPath: String,localName: String,itemCount: Int){
        guard let url = URL(string: urlPath) else {
            dispatchQueue.main.sync {
                self.leavedispatchGroup()
            }
            return
        }
       
        let urlRequest = URLRequest(url: url,cachePolicy: .reloadIgnoringLocalAndRemoteCacheData,timeoutInterval: 300)
        let downloadTask = session.downloadTask(with: urlRequest)
        self.localNameDict[downloadTask.taskIdentifier] = localName
        taskArray.append(downloadTask)
        
        downloadTask.resume()
        
    }

}

extension DataManager: URLSessionDownloadDelegate {
    
    func urlSession(_ session: URLSession,downloadTask: URLSessionDownloadTask,didFinishDownloadingTo location: URL) {
            do {
                let filemanager = FileManager()
                let documentsURL = filemanager.urls(for: .documentDirectory,in: .userDomainMask)[0]
                let fileURL = documentsURL.appendingPathComponent(self.localNameDict[downloadTask.taskIdentifier] ?? "img.jpeg")
                if filemanager.fileExists(atPath: fileURL.path){
                    try? filemanager.removeItem(at: fileURL)
                }
                try filemanager.copyItem(at: location,to: fileURL)
            }catch(let error) {
                print("ERROR In Storing: \(error.localizedDescription)")
            }
        
    }
    
    func urlSessionDidFinishEvents(forBackgroundURLSession session: URLSession) {
        dispatchQueue.main.async {
            guard let appDelegate = UIApplication.shared.delegate as? AppDelegate,let completionHandler = appDelegate.bgSessionCompletionHandler else {
                return
            }
            appDelegate.bgSessionCompletionHandler = nil
            completionHandler()
        }
    }

    func urlSession(_ session: URLSession,task: URLSessionTask,didCompleteWithError error: Error?) {
            if let error = error {
                print(error.localizedDescription)
            }
            self.leavedispatchGroup()
        
    }

    func leavedispatchGroup(){
        if dispatchGroupEnterCount > 0 {
                self.dispatchGroupEnterCount -= 1
                self.dispatchGroup.leave()
        }
    }
 }

App的运行视频: https://youtu.be/lNkMpZRNhGY

解决方法

extension URLSession {
    
    ///Background sessions let you perform uploads and downloads of content in the background while your app isn’t running. You can create a background session configuration by calling the backgroundSessionConfiguration(_:) method on the URLSessionConfiguration class.
    static let background = URLSession(
        configuration: .background(
            withIdentifier: "foo"))
}

您必须使用配置为在后台运行的会话。