I have a problem. I'm trying to make multiple downloads using NSURLSession, but I did not get what I'm doing wrong? This class is initialized once in class X. startDownload(realm.objects(Music)[indexPath.row]) may be called many times in the same class. Problems in the class 'Download', I know that for sure. If you need further information, please write
class Download: NSObject, NSURLSessionDelegate {
var progress: Float = 0.0
var progressBar: UIProgressView?
var addButton: UIButton?
private var downloadTask: [NSURLSessionDownloadTask] = []
private var backgroundSession: [NSURLSession] = []
private let realm = try! Realm()
private var downloadObject:[Music] = []
private var queueObjects:[Music] = []
func startDownload(object: Music? = nil) {
if (object != nil) {
self.queueObjects.append(object!)
}
let url = queueObjects[queueObjects.startIndex].url
if downloadTask.count < 3 {
let backgroundSessionConfiguration = NSURLSessionConfiguration.backgroundSessionConfigurationWithIdentifier("backgroundSession"+String(queueObjects.count))
backgroundSession.append(NSURLSession(configuration: backgroundSessionConfiguration, delegate: self, delegateQueue: NSOperationQueue.mainQueue()))
let sessionIndex = backgroundSession.endIndex-1
backgroundSession[sessionIndex].sessionDescription = String(sessionIndex)
downloadTask.append(backgroundSession[sessionIndex].downloadTaskWithURL(NSURL(string: url)!))
let taskIndex = downloadTask.endIndex-1
downloadTask[taskIndex].taskDescription = String(taskIndex)
downloadTask[taskIndex].resume()
downloadObject.append(queueObjects[queueObjects.startIndex])
queueObjects.removeAtIndex(queueObjects.startIndex)
}
}
func URLSession(session: NSURLSession, downloadTask: NSURLSessionDownloadTask, didFinishDownloadingToURL location: NSURL) {
let index = Int(downloadTask.taskDescription!)!
print("Index "+String(index))
let range = downloadObject[ index ].url.rangeOfString("?")!.startIndex.advancedBy(0)
let url = downloadObject[ index ].url[downloadObject[index].url.startIndex..<range]
let theFileName = (url as NSString).lastPathComponent
let path = NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory.DocumentDirectory, NSSearchPathDomainMask.UserDomainMask, true)
let directoryPath:String = path[0]
let fileManager = NSFileManager()
let destinationURLForFile = NSURL(fileURLWithPath: directoryPath.stringByAppendingString( "/"+theFileName))
if fileManager.fileExistsAtPath(destinationURLForFile.path!){
print(destinationURLForFile.path!)
saveObject(downloadObject[index], path: destinationURLForFile.path!)
}
else{
do {
try fileManager.moveItemAtURL(location, toURL: destinationURLForFile)
print(destinationURLForFile.path!)
saveObject(downloadObject[index], path: destinationURLForFile.path!)
} catch {
print("An error occurred while moving file to destination url")
}
}
if addButton != nil {
addButton?.hidden = true
}
downloadTask.cancel()
session.invalidateAndCancel()
self.backgroundSession[Int(session.sessionDescription!)!].invalidateAndCancel()
self.backgroundSession.removeAtIndex(Int(session.sessionDescription!)!)
self.downloadTask[Int(downloadTask.taskDescription!)!].cancel()
self.downloadTask.removeAtIndex(Int(downloadTask.taskDescription!)!)
}
func URLSession(session: NSURLSession, downloadTask: NSURLSessionDownloadTask, didWriteData bytesWritten: Int64, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64) {
progress = Float(totalBytesWritten)/Float(totalBytesExpectedToWrite)
if progressBar != nil {
progressBar?.progress = progress
}
}
private func saveObject(object: Music, path: String) {
let downloadMusic = DownloadMusic()
downloadMusic.id = object.id
downloadMusic.owner_id = object.owner_id
downloadMusic.artist = object.artist
downloadMusic.title = object.title
downloadMusic.duration = object.duration
downloadMusic.path = path
try! realm.write() {
realm.add(downloadMusic)
downloadObject.removeAtIndex(downloadObject.endIndex-1)
if self.queueObjects.count > 0 {
self.startDownload()
}
print(queueObjects.count)
print(downloadObject.count)
print(downloadMusic)
}
}
}
Thank you
First, don't do it that way. Let the session limit concurrency for you. Just throw all of the requests at it immediately.
Second, don't recreate a background session configuration unless your app just started up. You should create it exactly once and never again. The behavior of multiple NSURLSession objects pointing at the same identifier is, IIRC, undefined.
Third, don't invalidate the session until you're done with it. You're canceling all of your outstanding requests as soon as the first one finishes.
Fourth, you shouldn't be canceling the tasks unless you want to stop an in-progress task. If a task has already finished, canceling it does nothing.
Beyond that, I'm going to agree with the folks who said that you need to explain what the code is doing wrong before I can help further. :-)