【发布时间】:2015-11-26 07:41:00
【问题描述】:
我有一个应用程序,用户可以在其中按顺序下载多个文件。我已经关注Mr. Rob's solution 进行顺序下载。但是,当我尝试取消下载时遇到问题。
我尝试取消下载时有两种情况。
- 我想取消当前下载的文件。当我取消该文件时,下载可以继续到队列中的下一个文件
- 我想取消当前在队列中的文件。队列有 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