【问题标题】:How to Cancel download in Queue using Swift如何使用 Swift 取消队列中的下载
【发布时间】:2015-11-26 07:41:00
【问题描述】:

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

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

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

这是代码

下载管理器.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)
    }
}

下载操作.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)
        }
    }
}

异步操作.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()
    }

}

下载ViewController.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放在一个数组中,添加到队列中,一旦单击取消按钮,它将cancelAll()队列,从队列中删除取消并重新插入剩余的url回到数组中。但是,它不会起作用

谁能帮我满足这两种情况?

【问题讨论】:

标签: ios swift nsoperation nsoperationqueue


【解决方案1】:

您需要保留对NSOperation 实例的引用。然后你可以拨打cancel就可以了。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-09-28
    • 1970-01-01
    • 1970-01-01
    • 2020-11-17
    • 1970-01-01
    相关资源
    最近更新 更多