swift iOS - NSURLSession 无法正确下载多个文件
swift iOS - NSURLSession not downloading multiple files properly
我的应用程序同时下载多个文件。我的场景如下:
- 用户点击下载按钮。
- 一个下载 UITableViewCell 被初始化,实现 NSURLSessionDelegate 以下载指定文件。
- 开始下载。下载单元显示进度,因为文件正在使用 NSURLSession 提供的代表下载。
- 文件保存在本地文档文件夹中。
- 用户单击按钮清除所有已完成的下载。此按钮清除 Download Cell 使用的数组 'downloadQueue'。该按钮还调用 tableView.reloadData 来更新 tableView
问题是,当用户发起多次下载时,没有出现问题。所有文件同时正确下载。但是,当用户单击步骤 5 中描述的按钮,然后尝试下载另一个文件时,下载进度会立即显示 100% 完成。并且没有文件保存在本地。这可能是由于立即调用了 didFinishDownloadingToURL。
这是我的DownloadCell.swift
的完整代码
class DownloadCell: UITableViewCell, NSURLSessionDelegate {
@IBOutlet weak var lblSongName: UILabel!
@IBOutlet weak var progressBar: UIProgressView!
@IBOutlet weak var progressCount: UILabel!
var song: Song!
var task: NSURLSessionTask!
var percentageWritten: Float = 0.0
var taskTotalBytesWritten = 0
var taskTotalBytesExpectedToWrite = 0
lazy var session: NSURLSession = {
let config = NSURLSessionConfiguration.ephemeralSessionConfiguration()
config.allowsCellularAccess = false
let session = NSURLSession(configuration: config, delegate: self, delegateQueue: NSOperationQueue.mainQueue())
return session
}()
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
func startDownload() {
lblSongName.text = song.songName
if self.task != nil {
return
}
let url = NSURL(string: song.songDownloadLink)!
let req = NSMutableURLRequest(URL: url)
let task = self.session.downloadTaskWithRequest(req)
self.task = task
task.resume()
}
func URLSession(session: NSURLSession, downloadTask: NSURLSessionDownloadTask, didWriteData bytesWritten: Int64, totalBytesWritten writ: Int64, totalBytesExpectedToWrite exp: Int64) {
taskTotalBytesWritten = Int(writ)
taskTotalBytesExpectedToWrite = Int(exp)
percentageWritten = Float(taskTotalBytesWritten) / Float(taskTotalBytesExpectedToWrite)
progressBar.progress = percentageWritten
progressCount.text = String(Int(percentageWritten*100)) + "%"
print("(\(taskTotalBytesWritten) / \(taskTotalBytesExpectedToWrite))")
}
func URLSession(session: NSURLSession, task: NSURLSessionTask, didCompleteWithError error: NSError?) {
if error != nil {
print("Completed with error: \(error)")
}
}
func URLSession(session: NSURLSession, downloadTask: NSURLSessionDownloadTask, didFinishDownloadingToURL location: NSURL) {
do {
let documentsDirectoryURL = NSFileManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask).first as NSURL!
progressCount.text = "Done!"
progressBar.progress = 100.0
try NSFileManager().moveItemAtURL(location, toURL: documentsDirectoryURL.URLByAppendingPathComponent(song.songName + ".mp3"))
//Handling Badge Values
let tabBar = UIApplication.sharedApplication().keyWindow?.rootViewController as! UITabBarController
let downloadVC = tabBar.viewControllers?[1] as! DownloadViewController
let badgeValue = Int(downloadVC.tabBarItem.badgeValue!)! - 1
downloadVC.tabBarItem.badgeValue = String(badgeValue)
if badgeValue == 0 {
downloadVC.tabBarItem.badgeValue = nil
}
} catch {
print("Error occurred during saving.")
progressCount.text = String(error)
}
}
}
也许你应该实现 uitableviewcell 的 prepareForReuse 函数?如果这些单元格被重复使用,它们仍然可能有任务,所以开始下载 returns。进度条的值也没有重置为 0。
我的应用程序同时下载多个文件。我的场景如下:
- 用户点击下载按钮。
- 一个下载 UITableViewCell 被初始化,实现 NSURLSessionDelegate 以下载指定文件。
- 开始下载。下载单元显示进度,因为文件正在使用 NSURLSession 提供的代表下载。
- 文件保存在本地文档文件夹中。
- 用户单击按钮清除所有已完成的下载。此按钮清除 Download Cell 使用的数组 'downloadQueue'。该按钮还调用 tableView.reloadData 来更新 tableView
问题是,当用户发起多次下载时,没有出现问题。所有文件同时正确下载。但是,当用户单击步骤 5 中描述的按钮,然后尝试下载另一个文件时,下载进度会立即显示 100% 完成。并且没有文件保存在本地。这可能是由于立即调用了 didFinishDownloadingToURL。
这是我的DownloadCell.swift
的完整代码class DownloadCell: UITableViewCell, NSURLSessionDelegate {
@IBOutlet weak var lblSongName: UILabel!
@IBOutlet weak var progressBar: UIProgressView!
@IBOutlet weak var progressCount: UILabel!
var song: Song!
var task: NSURLSessionTask!
var percentageWritten: Float = 0.0
var taskTotalBytesWritten = 0
var taskTotalBytesExpectedToWrite = 0
lazy var session: NSURLSession = {
let config = NSURLSessionConfiguration.ephemeralSessionConfiguration()
config.allowsCellularAccess = false
let session = NSURLSession(configuration: config, delegate: self, delegateQueue: NSOperationQueue.mainQueue())
return session
}()
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
func startDownload() {
lblSongName.text = song.songName
if self.task != nil {
return
}
let url = NSURL(string: song.songDownloadLink)!
let req = NSMutableURLRequest(URL: url)
let task = self.session.downloadTaskWithRequest(req)
self.task = task
task.resume()
}
func URLSession(session: NSURLSession, downloadTask: NSURLSessionDownloadTask, didWriteData bytesWritten: Int64, totalBytesWritten writ: Int64, totalBytesExpectedToWrite exp: Int64) {
taskTotalBytesWritten = Int(writ)
taskTotalBytesExpectedToWrite = Int(exp)
percentageWritten = Float(taskTotalBytesWritten) / Float(taskTotalBytesExpectedToWrite)
progressBar.progress = percentageWritten
progressCount.text = String(Int(percentageWritten*100)) + "%"
print("(\(taskTotalBytesWritten) / \(taskTotalBytesExpectedToWrite))")
}
func URLSession(session: NSURLSession, task: NSURLSessionTask, didCompleteWithError error: NSError?) {
if error != nil {
print("Completed with error: \(error)")
}
}
func URLSession(session: NSURLSession, downloadTask: NSURLSessionDownloadTask, didFinishDownloadingToURL location: NSURL) {
do {
let documentsDirectoryURL = NSFileManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask).first as NSURL!
progressCount.text = "Done!"
progressBar.progress = 100.0
try NSFileManager().moveItemAtURL(location, toURL: documentsDirectoryURL.URLByAppendingPathComponent(song.songName + ".mp3"))
//Handling Badge Values
let tabBar = UIApplication.sharedApplication().keyWindow?.rootViewController as! UITabBarController
let downloadVC = tabBar.viewControllers?[1] as! DownloadViewController
let badgeValue = Int(downloadVC.tabBarItem.badgeValue!)! - 1
downloadVC.tabBarItem.badgeValue = String(badgeValue)
if badgeValue == 0 {
downloadVC.tabBarItem.badgeValue = nil
}
} catch {
print("Error occurred during saving.")
progressCount.text = String(error)
}
}
}
也许你应该实现 uitableviewcell 的 prepareForReuse 函数?如果这些单元格被重复使用,它们仍然可能有任务,所以开始下载 returns。进度条的值也没有重置为 0。