Swift cancellation of NSOperationQueue does not work - ios

I'm trying to cancel NSOperationQueue process using method cancelAllOperations() using swift but it does not work.
I am downloading a file from url when i cancel the download it doesn't work.
here is the code i am using:
var s = NSOperationQueue.mainQueue()
lazy var session : NSURLSession = {
let config = NSURLSessionConfiguration.ephemeralSessionConfiguration()
config.allowsCellularAccess = false
let session = NSURLSession(configuration: config, delegate: self, delegateQueue: self.s)
return session
}
override func viewDidLoad() {
progressBar.setProgress(0.0, animated: true) //set progressBar to 0 at start
}
#IBAction func cancel(sender: AnyObject) {
s.cancelAllOperations()
}
func URLSession(session: NSURLSession, downloadTask: NSURLSessionDownloadTask, didWriteData bytesWritten: Int64, totalBytesWritten writ: Int64, totalBytesExpectedToWrite exp: Int64) {
print("downloaded \(100*writ/exp)")
dispatch_async(dispatch_get_main_queue(), {
self.counter = Float(100*writ/exp)
return
})
}
func URLSession(session: NSURLSession, downloadTask: NSURLSessionDownloadTask, didResumeAtOffset fileOffset: Int64, expectedTotalBytes: Int64) {
// unused in this example
}
func URLSession(session: NSURLSession, task: NSURLSessionTask, didCompleteWithError error: NSError?) {
print("completed: error: \(error)")
if(error != nil){
}
}
// this is the only required NSURLSessionDownloadDelegate method
func URLSession(session: NSURLSession, downloadTask: NSURLSessionDownloadTask, didFinishDownloadingToURL location: NSURL) {
let path = NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory.DocumentDirectory, NSSearchPathDomainMask.UserDomainMask, true)
let documentDirectoryPath:String = path[0]
let fileManager = NSFileManager()
let destinationURLForFile = NSURL(fileURLWithPath: documentDirectoryPath.stringByAppendingString("Music.mp3"))
if fileManager.fileExistsAtPath(destinationURLForFile.path!){
print("File Already Exists")
}
else{
do {
try fileManager.moveItemAtURL(location, toURL: destinationURLForFile)
print("File doesn't exists")
}catch{
print("An error occurred while moving file to destination url")
}
}
}

Related

Download with URLSession and Operation queue does not start next operation when application is in background

Use case : Download file from a server via one API which will give the download server url(download server url vality is for 10 secs only).
I have enabled the background capabilities.
Then created one Download Manager which holds the OperationQueue for download data task.
In Operation class when main() function calls, I have makes the API call which will return the download server URL and started a download.
Works fine in debug mode but does not work in release mode.
Download Manager :
final class SCDownloadManager: NSObject {
#objc static var shared = SCDownloadManager()
private override init() {
super.init()
NotificationCenter.default.addObserver(self, selector: #selector(SCDownloadManager.networkDidChange(_:)), name: NSNotification.Name.init(NetworkConnectionChanged), object: nil)
}
/// Dictionary of operations, keyed by the `Download URL` of the `URLSessionTask`
fileprivate var operations = [URL: SCDownloadOperation]()
fileprivate var serverURLRequestMap = [URL: SCDownloadOperation]()
/// Serial NSOperationQueue for downloads
private let queue: OperationQueue = {
let _queue = OperationQueue()
_queue.name = "SCDownloadManagerQueue"
_queue.maxConcurrentOperationCount = 3
return _queue
}()
/// Delegate-based NSURLSession for DownloadManager
lazy var downloadSession: URLSession = {
let configuration = URLSessionConfiguration.background(withIdentifier: "com.xyz.background.download")
let sessionQueue = OperationQueue()
return URLSession(configuration: configuration, delegate: self, delegateQueue: sessionQueue)
}()
lazy var dataSession: URLSession = {
let configuration = URLSessionConfiguration.background(withIdentifier: "com.xyz.background.url")
let sessionQueue = OperationQueue()
return URLSession(configuration: configuration, delegate: self, delegateQueue: sessionQueue)
}()
#discardableResult
#objc func addDownload(_ downloadRecord: DownloadRecord) -> SCDownloadOperation {
let operation = SCDownloadOperation(withDownloadRecord: downloadRecord)
operation.delegate = self
operations[downloadRecord.downloadUrl] = operation
queue.addOperation(operation)
return operation
}
/// Cancel all queued operations
#objc func cancelAll() {
queue.cancelAllOperations()
}
#objc func networkDidChange(_ notification: Notification) {
if let reachability = notification.object as? Reachability {
if reachability.currentReachabilityStatus() == NotReachable {
cancelAll()
}
}
}
}
//MARK:- Download operation delegate
extension SCDownloadManager: SCDownloadOperationDelegate {
func getServerDownloadUrl(forRequest request: URLRequest, ofOperation operation: SCDownloadOperation) {
if let url = request.url {
serverURLRequestMap[url] = operation
}
self.dataSession.downloadTask(with: request).resume()
}
}
// MARK: URLSessionDownloadDelegate methods
extension SCDownloadManager: URLSessionDownloadDelegate {
func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL) {
guard let sourceURL = downloadTask.originalRequest?.url else { return }
if session == dataSession {
if FileManager.default.isReadableFile(atPath: location.path) {
if let data = FileManager.default.contents(atPath: location.path) {
if let downloadOperation = serverURLRequestMap[sourceURL] {
if let serverUrl = String(data: data, encoding: .utf8), let downloadServerUrl = URL(string: serverUrl) {
self.operations.changeKey(from: downloadOperation.downloadRecord.downloadUrl, to: downloadServerUrl)
downloadOperation.downloadRecord.downloadUrl = downloadServerUrl
if let url = downloadOperation.downloadRecord.downloadUrl {
downloadOperation.downloadRecord.downloadTask = downloadSession.downloadTask(with: url)
downloadOperation.downloadRecord.downloadTask.resume()
}
}
}
do {
try FileManager.default.removeItem(at: location)
} catch {
print("error while removing file from default location")
}
}
}
} else {
operations[sourceURL]?.urlSession(session, downloadTask: downloadTask, didFinishDownloadingTo: location)
}
}
func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didWriteData bytesWritten: Int64, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64) {
if session == self.downloadSession {
guard let sourceURL = downloadTask.originalRequest?.url else { return }
operations[sourceURL]?.urlSession(session, downloadTask: downloadTask, didWriteData: bytesWritten, totalBytesWritten: totalBytesWritten, totalBytesExpectedToWrite: totalBytesExpectedToWrite)
}
}
}
// MARK: URLSessionTaskDelegate methods
extension SCDownloadManager: URLSessionTaskDelegate {
func urlSessionDidFinishEvents(forBackgroundURLSession session: URLSession) {
if downloadSession == session {
DispatchQueue.main.async {
if let completionHandler = Constants.appDelegate.backgroundTransferCompletionHandler {
Constants.appDelegate.backgroundTransferCompletionHandler = nil
completionHandler()
}
}
}
}
func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) {
guard let sourceURL = task.originalRequest?.url else { return }
if session == dataSession {
if error == nil {
} else {
print("got error while doing API on download task")
}
} else {
operations[sourceURL]?.urlSession(session, task: task, didCompleteWithError: error)
operations.removeValue(forKey: sourceURL)
}
}
}
Operation Class :
class SCDownloadOperation: SCAsynchronousOperation {
let downloadRecord: DownloadRecord
var getServerDownloadUrl: ((URLRequest)->Void)?
weak var delegate: SCDownloadOperationDelegate?
init(withDownloadRecord dr: DownloadRecord) {
downloadRecord = dr
super.init()
}
override func cancel() {
if let task = downloadRecord.downloadTask{
task.cancel()
}
super.cancel()
}
override func main() {
switch downloadRecord.downloadDataType {
case DOWNLOAD_DATA_TYPE_CONTENT:
let configuration = RequestConfiguration(withMethodType: .GET, urlString: downloadRecord.downloadUrl.absoluteString)
if let request = NetworkManager.sharedInstance.urlRequest(forRequestConfiguration: configuration) {
delegate?.getServerDownloadUrl(forRequest: request, ofOperation: self)
}
default: break
}
}
}
// MARK: NSURLSessionDownloadDelegate methods
extension SCDownloadOperation: URLSessionDownloadDelegate {
func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL) {
downloadRecord.progress = 1
switch downloadRecord.downloadDataType {
case DOWNLOAD_DATA_TYPE_CONTENT:
processDownloadFinish(atLocation: location)
default: break
}
}
func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didWriteData bytesWritten: Int64, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64) {
downloadRecord.isExecuting = true
downloadRecord.isDownloadProgressAvailable = true
let downloadProgress = Float(totalBytesWritten) / Float(totalBytesExpectedToWrite)
downloadRecord.progress = downloadProgress
downloadRecord.percentComplete = ((Float(totalBytesWritten) / Float(totalBytesExpectedToWrite))*100)
downloadRecord.downloadProgress = downloadProgress
switch downloadRecord.downloadDataType {
case DOWNLOAD_DATA_TYPE_CONTENT:
updateWrittenData()
default: break
}
}
}
// MARK: NSURLSessionTaskDelegate methods
extension SCDownloadOperation: URLSessionTaskDelegate {
func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) {
completeOperation()
if error != nil {
print("\(String(describing: error))")
switch downloadRecord.downloadDataType {
case DOWNLOAD_DATA_TYPE_CONTENT:
contentDownloadFail()
default: break
}
}
}
}

UIdocumentInteractionController cant display the PDF file in swift 4

class ViewController: UIViewController,UIDocumentInteractionControllerDelegate
{
let documentInteractionController = UIDocumentInteractionController(url: URL(fileURLWithPath: path))
documentInteractionController.delegate = self
documentInteractionController.presentPreview(animated: true)
}
func documentInteractionControllerViewControllerForPreview(_ controller: UIDocumentInteractionController) -> UIViewController
{
return self
}
above code i try on my apps, when click left menu , not able to show the pdf file. anyone got idea ?
I am showing here an example for download pdf from url link displaying in UIdocumentInteractionController in swift 4 as per your requirement
class ExampleViewController: UIViewController, URLSessionDownloadDelegate, UIDocumentInteractionControllerDelegate {
let urlLink = "sample link";
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func btnDownArrowOnPressed(_ sender: UIButton) {
if(urlLink != nil){
if(urlLink != nil && urlLink != "Null" && urlLink != ""){
let backgroundSessionConfiguration = URLSessionConfiguration.background(withIdentifier: "backgroundSession")
backgroundSession = Foundation.URLSession(configuration: backgroundSessionConfiguration, delegate: self, delegateQueue: OperationQueue.main)
let url = URL(string: urlLink!
downloadTask = backgroundSession.downloadTask(with: url)
downloadTask.resume()
}else{
self.view.makeToast("You don't have any certificate to download.")
}
}
else{
self.view.makeToast("You don't have any certificate to download.")
}
}
func showFileWithPath(path: String){
let isFileFound:Bool? = FileManager.default.fileExists(atPath: path)
if isFileFound == true{
let viewer = UIDocumentInteractionController(url: URL(fileURLWithPath: path))
viewer.delegate = self
viewer.presentPreview(animated: true)
}
}
func urlSession(_ session: URLSession,
downloadTask: URLSessionDownloadTask,
didFinishDownloadingTo location: URL){
let path = NSSearchPathForDirectoriesInDomains(FileManager.SearchPathDirectory.documentDirectory, FileManager.SearchPathDomainMask.userDomainMask, true)
let documentDirectoryPath:String = path[0]
let fileManager = FileManager()
let destinationURLForFile = URL(fileURLWithPath: documentDirectoryPath.appendingFormat("/Certificate.pdf"))
if fileManager.fileExists(atPath: destinationURLForFile.path){
showFileWithPath(path: destinationURLForFile.path)
}
else{
do {
try fileManager.moveItem(at: location, to: destinationURLForFile)
// show file
showFileWithPath(path: destinationURLForFile.path)
}catch{
print("An error occurred while moving file to destination url")
}
}
}
// 2
func urlSession(_ session: URLSession,
downloadTask: URLSessionDownloadTask,
didWriteData bytesWritten: Int64,
totalBytesWritten: Int64,
totalBytesExpectedToWrite: Int64){
}
//MARK: URLSessionTaskDelegate
func urlSession(_ session: URLSession,
task: URLSessionTask,
didCompleteWithError error: Error?){
downloadTask = nil
if (error != nil) {
print(error!.localizedDescription)
}else{
self.view.hideToastActivity()
print("The task finished transferring data successfully")
}
}
//MARK: UIDocumentInteractionControllerDelegate
func documentInteractionControllerViewControllerForPreview(_ controller: UIDocumentInteractionController) -> UIViewController
{
UINavigationBar.appearance().tintColor = UIColor.white
return self
}
}
Use URL(string: path) instead of URL(fileURLWithPath: path)

Migrating code from NSURLConnection to NSURLSession [duplicate]

In the following code, the file downloads just fine. However none of the delegate methods seem to be called as I receive no output whatsoever. the progressView is not updated either. Any idea why?
import Foundation
import UIKit
class Podcast: PFQueryTableViewController, UINavigationControllerDelegate, MWFeedParserDelegate, UITableViewDataSource, NSURLSessionDelegate, NSURLSessionDownloadDelegate {
func downloadEpisodeWithFeedItem(episodeURL: NSURL) {
var request: NSURLRequest = NSURLRequest(URL: episodeURL)
let config = NSURLSessionConfiguration.defaultSessionConfiguration()
let session = NSURLSession(configuration: config, delegate: self, delegateQueue: nil)
var downloadTask = session.downloadTaskWithURL(episodeURL, completionHandler: { (url, response, error) -> Void in
println("task completed")
if (error != nil) {
println(error.localizedDescription)
} else {
println("no error")
println(response)
}
})
downloadTask.resume()
}
func URLSession(session: NSURLSession, downloadTask: NSURLSessionDownloadTask, didResumeAtOffset fileOffset: Int64, expectedTotalBytes: Int64) {
println("didResumeAtOffset")
}
func URLSession(session: NSURLSession, downloadTask: NSURLSessionDownloadTask, didWriteData bytesWritten: Int64, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64) {
var downloadProgress = Double(totalBytesWritten) / Double(totalBytesExpectedToWrite)
println(Float(downloadProgress))
println("sup")
epCell.progressView.progress = Float(downloadProgress)
}
func URLSession(session: NSURLSession, downloadTask: NSURLSessionDownloadTask, didFinishDownloadingToURL location: NSURL) {
println(location)
}
}
From my testing, you have to choose whether you want to use a delegate or a completion handler - if you specify both, only the completion handler gets called. This code gave me running progress updates and the didFinishDownloadingToURL event:
func downloadEpisodeWithFeedItem(episodeURL: NSURL) {
let request: NSURLRequest = NSURLRequest(URL: episodeURL)
let config = NSURLSessionConfiguration.defaultSessionConfiguration()
let session = NSURLSession(configuration: config, delegate: self, delegateQueue: NSOperationQueue.mainQueue())
let downloadTask = session.downloadTaskWithURL(episodeURL)
downloadTask.resume()
}
func URLSession(session: NSURLSession, downloadTask: NSURLSessionDownloadTask, didResumeAtOffset fileOffset: Int64, expectedTotalBytes: Int64) {
println("didResumeAtOffset: \(fileOffset)")
}
func URLSession(session: NSURLSession, downloadTask: NSURLSessionDownloadTask, didWriteData bytesWritten: Int64, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64) {
var downloadProgress = Double(totalBytesWritten) / Double(totalBytesExpectedToWrite)
println("downloadProgress: \(downloadProgress)")
}
func URLSession(session: NSURLSession, downloadTask: NSURLSessionDownloadTask, didFinishDownloadingToURL location: NSURL) {
println("didFinishDownloadingToURL: \(location)")
println(downloadTask)
}
From the NSURLSession documentation, here's the relevant section:
Like most networking APIs, the NSURLSession API is highly asynchronous. It returns data in one of two ways, depending on the methods you call:
To a completion handler block that returns data to your app when a transfer finishes successfully or with an error.
By calling methods on your custom delegate as the data is received.
By calling methods on your custom delegate when download to a file is complete.
So by design it returns data to either a completion handler block or a delegate. But as evinced here, not both.
Interestingly, Apple specifically explains this behavior in their NSURLSessionDataDelegate (but neither in the base delegate NSURLSessionTaskDelegate nor in NSURLSessionDownloadDelegate)
NOTE
An NSURLSession object need not have a delegate. If no delegate is assigned, when you create tasks in that session, you must provide a completion handler block to obtain the data.
Completion handler block are primarily intended as an alternative to using a custom delegate. If you create a task using a method that takes a completion handler block, the delegate methods for response and data delivery are not called.
Swift 3
class ViewController: UIViewController {
var urlLink: URL!
var defaultSession: URLSession!
var downloadTask: URLSessionDownloadTask!
}
// MARK: Button Pressed
#IBAction func btnDownloadPressed(_ sender: UIButton) {
let urlLink1 = URL.init(string: "https://github.com/VivekVithlani/QRCodeReader/archive/master.zip")
startDownloading(url: urlLink!)
}
#IBAction func btnResumePressed(_ sender: UIButton) {
downloadTask.resume()
}
#IBAction func btnStopPressed(_ sender: UIButton) {
downloadTask.cancel()
}
#IBAction func btnPausePressed(_ sender: UIButton) {
downloadTask.suspend()
}
func startDownloading (url:URL) {
let backgroundSessionConfiguration = URLSessionConfiguration.background(withIdentifier: "backgroundSession")
defaultSession = Foundation.URLSession(configuration: backgroundSessionConfiguration, delegate: self, delegateQueue: OperationQueue.main)
downloadProgress.setProgress(0.0, animated: false)
downloadTask = defaultSession.downloadTask(with: urlLink)
downloadTask.resume()
}
// MARK:- URLSessionDownloadDelegate
func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL) {
print("File download succesfully")
}
func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didWriteData bytesWritten: Int64, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64) {
downloadProgress.setProgress(Float(totalBytesWritten)/Float(totalBytesExpectedToWrite), animated: true)
}
func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) {
downloadTask = nil
downloadProgress.setProgress(0.0, animated: true)
if (error != nil) {
print("didCompleteWithError \(error?.localizedDescription)")
}
else {
print("The task finished successfully")
}
}

iOS-Swift How to update progressView

I am developing an app where i am downloading data from web.
here i am using cancel button to cancel the download progress,this works fine if i am in the same view controller and if i navigate to new view controller and return back to download view controller progress view is not updating but the download is happening.
This is the code i am using to download data
func URLSession(session: NSURLSession,
downloadTask: NSURLSessionDownloadTask,
didFinishDownloadingToURL location: NSURL){
let path = NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory.DocumentDirectory, NSSearchPathDomainMask.UserDomainMask, true)
let documentDirectoryPath:String = path[0]
let fileManager = NSFileManager()
let destinationURLForFile = NSURL(fileURLWithPath: documentDirectoryPath.stringByAppendingString( Variables.name ))
if fileManager.fileExistsAtPath(destinationURLForFile.path!){
print("File Already Exists")
} else {
do {
try fileManager.moveItemAtURL(location, toURL: destinationURLForFile)
print("File doesn't exists")
}catch{
print("An error occurred while moving file to destination url")
}
}
}
// 2
func URLSession(session: NSURLSession,
downloadTask: NSURLSessionDownloadTask,
didWriteData bytesWritten: Int64,
totalBytesWritten writ: Int64,
totalBytesExpectedToWrite exp: Int64){
//progressView.setProgress(Float(totalBytesWritten)/Float(totalBytesExpectedToWrite), animated: true)
print("downloaded \(100*writ/exp)")
dispatch_async(dispatch_get_main_queue(), {
self.counter = Float(100*writ/exp)
return
})
}
func URLSession(session: NSURLSession,
task: NSURLSessionTask,
didCompleteWithError error: NSError?){
downloadTask = nil
// progressView.setProgress(0.0, animated: true)
if (error != nil) {
print(error?.description)
} else {
print("The task finished transferring data successfully")
}
}
func documentInteractionControllerViewControllerForPreview(controller: UIDocumentInteractionController) -> UIViewController{
return self
}

How to Cancel download in Queue using Swift

I have an app where user can download multiple files, sequentially. I have followed Mr. Rob's solution for the sequential downloads. However, I have problem when I try to cancel the download.
There are two situation when I try to cancel the download.
I want to cancel the current downloading file. When I cancel that file, the download can proceed to the next file in the queue
I want to cancel the file that are currently in the queue. The queue has cancelAll() method which will cancel all file in the queue.
Here is the codes
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
This is where I want to cancel the download.
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)
}
For situation 1, I have tried to use do
queue.operations[identifier].cancel()
but it crash saying
*** Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[__NSArrayI objectAtIndex:]: index 1 beyond bounds [0 .. 0]'
For situation 2, I have tried to put all downloaded urls in an array, add into queue, once the cancel button is clicked, it will cancelAll() queue, remove the cancel one from queue and re-insert the remaining urls back into the array. However, it won't work
Can anybody help me to satisfy both situation?
You need to keep a reference to the NSOperation instance. Then you can call cancel on it.

Resources