如何在并发模式下从多个URL下载数据?

时间:2015-06-24 10:11:01

标签: swift cocoa-touch ios8 nsoperation nsoperationqueue

我试过这个link只下载一个网址。成功地暂停和恢复工作。

现在我正在尝试多个URL(即5个URL)。如果第二个URL正在进行,那么如果我开始第三个URL意味着,则第二个URL停止。

我不知道在并发中运行所有url。我试过NSOperationQueue。但我不知道确切的语法,也不知道如何在队列中添加任务。

我的网址链接之间不应该有任何中断。怎么做?

我的代码:

var dict = [NSURLSessionTask:Int]()

lazy var session : NSURLSession = {
        let config = NSURLSessionConfiguration.ephemeralSessionConfiguration()

        config.allowsCellularAccess = false
        let session = NSURLSession(configuration: config, delegate: self, delegateQueue: NSOperationQueue.mainQueue())

        println(session)
        return session

        }()

func URLSession(session: NSURLSession, downloadTask: NSURLSessionDownloadTask, didWriteData bytesWritten: Int64, totalBytesWritten writ: Int64, totalBytesExpectedToWrite exp: Int64) {
        if let numberOfTask = dict[downloadTask]
    {
        println("which task is this\(dict[downloadTask])")

        println("downloaded \(100*writ/exp)")
        taskTotalBytesWritten = Int(writ)
        taskTotalBytesExpectedToWrite = Int(exp)
        percentageWritten = Float(taskTotalBytesWritten) / Float(taskTotalBytesExpectedToWrite)

        downLoadTblVw.delegate = self
        downLoadTblVw.reloadData()
    }
     }

    func URLSession(session: NSURLSession, downloadTask: NSURLSessionDownloadTask, didResumeAtOffset fileOffset: Int64, expectedTotalBytes: Int64) {


        // unused in this example
    }

    func URLSession(session: NSURLSession, task: NSURLSessionTask, didCompleteWithError error: NSError?) {
        println("completed: error: \(error)")
    }

    // this is the only required NSURLSessionDownloadDelegate method

    func URLSession(session: NSURLSession, downloadTask: NSURLSessionDownloadTask, didFinishDownloadingToURL location: NSURL) {

        let documentsDirectoryURL =  NSFileManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask).first as NSURL
        println("Finished downloading!")
        println(documentsDirectoryURL)
        var err:NSError?

        // Here you can move your downloaded file
        if NSFileManager().moveItemAtURL(location, toURL: documentsDirectoryURL.URLByAppendingPathComponent(downloadTask.response!.suggestedFilename!), error: &err) {
            println("File saved")
        } else {
            if let err = err {
                println("File not saved.\n\(err.description)")

            }
        }

    }



    @IBAction func startDownload(sender: UIButton) {
        var btnPos: CGPoint = sender.convertPoint(CGPointZero, toView: downLoadTblVw)
        var indePath: NSIndexPath = downLoadTblVw.indexPathForRowAtPoint(btnPos)!

        println("INDE\(indePath.row)")

        buttonTag = indePath.row

        if self.task != nil {

            println("PRESSED TASK NIL")
            return
        }

        switch(buttonTag)
        {
        case 0:

            var myQueue = NSOperationQueue()
            myQueue.addOperationWithBlock({

                let s = "https://developer.apple.com/library/ios/documentation/UserExperience/Conceptual/MobileHIG/MobileHIG.pdf"
                let url = NSURL(string:s)!
                let req = NSMutableURLRequest(URL:url)
                let task = self.session.downloadTaskWithRequest(req)
                self.task = task

                dict[task] = 0
                println("SESSION -> task \(task)")

                task.resume()
                println("PRESSED SECOND TIME")
            })
            break

        case 1:

  let s = "https://developer.apple.com/library/ios/documentation/iphone/conceptual/iphoneosprogrammingguide/iphoneappprogrammingguide.pdf"
            let url = NSURL(string:s)!
            let req = NSMutableURLRequest(URL:url)

            var myQueue = NSOperationQueue()
            myQueue.addOperationWithBlock({

                let task = self.session.downloadTaskWithRequest(req)
                self.task_1 = task
                dict[task_1] = 1
                println("SESSION _1-> task \(task)")
                task.resume()

                })
            break

        case 2:

            let s = "http://manuals.info.apple.com/MANUALS/1000/MA1565/en_US/iphone_user_guide.pdf"
            let url = NSURL(string:s)!
            let req = NSMutableURLRequest(URL:url)
            let task = self.session.downloadTaskWithRequest(req)
            self.task_2 = task
            dict[task_2] = 2
            println("SESSION _2-> task \(task)")
            task.resume()
            break

        case 3:

            let s = "https://developer.apple.com/library/ios/documentation/AudioVideo/Conceptual/AVFoundationPG/AVFoundationPG.pdf"
            let url = NSURL(string:s)!
            let req = NSMutableURLRequest(URL:url)
            let task = self.session.downloadTaskWithRequest(req)
            self.task_3 = task
            dict[task_3] = 3
            println("SESSION _3-> task \(task)")
            task.resume()

            break
        default:
            println("WRONG BUTTON PRESSED")
            break
        }
      }

2 个答案:

答案 0 :(得分:0)

您可以使用库Alamofire来处理这种情况。本质是使用多个线程从URL获取数据并调用一些回调函数来处理数据。你可以阅读图书馆的文档。

答案 1 :(得分:0)

您的下载代码看起来很好。按下按钮后,将开始下载任务。 (例如,如果我单击button_2和button_3,将同时下载2和3的下载任务)

代码中的缺陷位于

func URLSession(session: NSURLSession, 
                downloadTask: NSURLSessionDownloadTask, 
                didWriteData bytesWritten: Int64, 
                totalBytesWritten writ: Int64, 
                totalBytesExpectedToWrite exp: Int64)

由于您希望跟踪每项任务的进度,因此您必须找到发送此代理呼叫的downloadTask

要跟踪哪个任务触发代理,您可以执行类似这样的操作

let dict = [NSURLSessionTask:Int]()

let task1 = session.DownloadTaskWithURL( ..... ) 
let task2 = session.DownloadTaskWithURL( ..... ) 

dict[task1] = 0
dict[task2] = 1

并且在委托调用中,您可以将任务对应于您设置的数字

func URLSession(session: NSURLSession, downloadTask: NSURLSessionDownloadTask, didWriteData bytesWritten: Int64, totalBytesWritten writ: Int64, totalBytesExpectedToWrite exp: Int64) {
    if let numberOfTask = dict[downloadTask]{
        progress[numberOfTask] = Float(taskTotalBytesWritten) / Float(taskTotalBytesExpectedToWrite)
        downLoadTblVw.reloadData()
    }
}