如何使用Swift取消在队列中的下载

时间:2015-11-26 07:41:00

标签: ios swift nsoperation nsoperationqueue

我有一个应用程序,用户可以按顺序下载多个文件。我已按照Mr. Rob's solution进行顺序下载。但是,当我尝试取消下载时,我遇到了问题。

我尝试取消下载时有两种情况。

  1. 我想取消当前的下载文件。当我取消该文件时,下载可以继续进入队列中的下一个文件
  2. 我想取消当前在队列中的文件。该队列具有cancelAll()方法,该方法将取消队列中的所有文件。
  3. 以下是代码

    DownloadManager.swift

    class DownloadManager: NSObject, NSURLSessionTaskDelegate, NSURLSessionDownloadDelegate
    {
    
        /// Dictionary of operations, keyed by the `taskIdentifier` of the `NSURLSessionTask`
        internal var delegate : DownloadVC!
        private var operations = [Int: DownloadOperation]()
    
        /// Serial NSOperationQueue for downloads
    
        let queue: NSOperationQueue = {
            let _queue = NSOperationQueue()
            _queue.name = "download"
            _queue.maxConcurrentOperationCount = 1
            return _queue
        }()
    
        /// Delegate-based NSURLSession for DownloadManager
    
        lazy var session: NSURLSession = {
            let sessionConfiguration = NSURLSessionConfiguration.defaultSessionConfiguration()
            return NSURLSession(configuration: sessionConfiguration, delegate: self, delegateQueue: nil)
        }()
    
        /// Add download
        ///
        /// - parameter URL:  The URL of the file to be downloaded
        ///
        /// - returns: The DownloadOperation of the operation that was queued
    
        func addDownload(URL: NSURL) -> DownloadOperation
        {
            print("url in download manager: \(URL)")
            let operation = DownloadOperation(session: session, URL: URL)
            operations[operation.task.taskIdentifier] = operation
            queue.addOperation(operation)
            return operation
        }
    
        /// Cancel all queued operations
    
        func cancelAll()
        {
            queue.cancelAllOperations()
    
        }
    
    //    func cancelOne()
    //    {
    //        operations[identifier]?.cancel()
    //        print("identifier : \(identifier)")
    //        //queue.operations[identifier].cancel()
    //       // cancelAll()
    //    }
    
        // MARK: NSURLSessionDownloadDelegate methods
    
        func URLSession(session: NSURLSession,
            downloadTask: NSURLSessionDownloadTask,
            didFinishDownloadingToURL location: NSURL)
        {
            print("downloadTask.taskIdentifier \(downloadTask.taskIdentifier)")
            operations[downloadTask.taskIdentifier]?.delegate = delegate
            operations[downloadTask.taskIdentifier]?.URLSession(session, downloadTask: downloadTask, didFinishDownloadingToURL: location)
        }
    
        func URLSession(session: NSURLSession,
            downloadTask: NSURLSessionDownloadTask,
            didWriteData bytesWritten: Int64,
            totalBytesWritten: Int64,
            totalBytesExpectedToWrite: Int64)
        {
            operations[downloadTask.taskIdentifier]?.delegate = delegate
            operations[downloadTask.taskIdentifier]?.URLSession(session, downloadTask: downloadTask, didWriteData: bytesWritten, totalBytesWritten: totalBytesWritten, totalBytesExpectedToWrite: totalBytesExpectedToWrite)
        }
    
        // MARK: NSURLSessionTaskDelegate methods
    
        func URLSession(session: NSURLSession,
            task: NSURLSessionTask,
            didCompleteWithError error: NSError?)
        {
                let key = task.taskIdentifier
                operations[key]?.URLSession(session, task: task, didCompleteWithError: error)
                operations.removeValueForKey(key)
        }
    }
    

    DownloadOperation.swift

    class DownloadOperation : AsynchronousOperation
    {
        let task: NSURLSessionTask
        var percentageWritten:Float = 0.0
        var delegate : DataDelegate!
    
        init(session: NSURLSession, URL: NSURL)
        {
            task = session.downloadTaskWithURL(URL)
            super.init()
        }
    
        override func cancel() {
            task.cancel()
            super.cancel()
        }
    
        override func main() {
            task.resume()
    
        }
    
        // MARK: NSURLSessionDownloadDelegate methods
    
            func URLSession(session: NSURLSession,
                downloadTask: NSURLSessionDownloadTask,
                didWriteData bytesWritten: Int64,
                totalBytesWritten write: Int64,
                totalBytesExpectedToWrite expect: Int64)
            {
                //download bar progress
                percentageWritten = Float(write) / Float(expect)
                //progressBar.progress = percentageWritten
                let pW = Int(percentageWritten*100)
                delegate.didWriteData(pW)
            }
    
            // using cocoa Security for encryption and decryption
            func URLSession(session: NSURLSession,
                downloadTask: NSURLSessionDownloadTask,
                didFinishDownloadingToURL location: NSURL)
            {
                let documentsDirectoryURL =  NSFileManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask).first as NSURL?
                print("Finished downloading!")
                print(documentsDirectoryURL)
                let downloadLocation = "\(location)".stringByReplacingOccurrencesOfString("file://", withString: "")
    
                let fileData = NSFileManager().contentsAtPath(downloadLocation)
    
                delegate.didFinishDownloadingToUrl(fileData!)
            }
    
    
        // MARK: NSURLSessionTaskDelegate methods
    
        func URLSession(session: NSURLSession,
            task: NSURLSessionTask,
            didCompleteWithError error: NSError?)
        {
            completeOperation()
            if error != nil {
                print(error)
            }
        }
    }
    

    AsynchronousOperation.swift

    class AsynchronousOperation : NSOperation
    {
    
        override var asynchronous: Bool { return true }
    
        private var _executing: Bool = false
        override var executing: Bool
            {
            get
            {
                return _executing
            }
            set {
                if (_executing != newValue)
                {
                    self.willChangeValueForKey("isExecuting")
                    _executing = newValue
                    self.didChangeValueForKey("isExecuting")
                }
            }
        }
    
        private var _finished: Bool = false
        override var finished: Bool
            {
            get
            {
                return _finished
            }
            set
            {
                if (_finished != newValue)
                {
                    self.willChangeValueForKey("isFinished")
                    _finished = newValue
                    self.didChangeValueForKey("isFinished")
                }
            }
        }
    
        func completeOperation()
        {
            if executing {
                executing = false
                finished = true
            }
        }
    
        override func start()
        {
            if (cancelled) {
                finished = true
                executing = false
                return
            }
    
            executing = true
    
            main()
        }
    
    }
    

    DownloadViewController.swift

    这是我想要取消下载的地方。

     if cell.downloadLabel.currentTitle == "CANCEL"
            {
                print("cancel button was pressed")
    
                downloadManager.cancelAll()
    
    // I want to put the codes here
    
                let defaults: NSUserDefaults = NSUserDefaults.standardUserDefaults()
                let key = cell.stringId
                print("key : \(key)")
                defaults.setBool(false, forKey: key)
                defaults.synchronize()
    
                cell.accessoryType = UITableViewCellAccessoryType.None
                cell.downloadLabel.backgroundColor = UIColor.redColor()
                cell.downloadLabel.setTitle("DOWNLOAD", forState: .Normal)
            }
    

    对于情况1,我尝试使用do

    queue.operations[identifier].cancel()
    

    但它崩溃说

    *** Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[__NSArrayI objectAtIndex:]: index 1 beyond bounds [0 .. 0]'
    

    对于情况2,我试图将所有下载的URL放入一个数组中,添加到队列中,一旦单击取消按钮,它将取消所有()队列,从队列中删除取消的URL并重新插入剩余的URL回到阵列。但是,它不会工作

    有人能帮助我满足这两种情况吗?

1 个答案:

答案 0 :(得分:2)

您需要保留对A实例的引用。然后你可以打电话给NSOperation