Search code examples
iosiphonemultithreadingswiftnsoperationqueue

cancellation of NSOperationQueue does not work in swift


I'm trying to cancel all the threads in NSOperationQueue using swift but it does not work.

I'm trying start and stop the thread using NSOperationQueue when user clicks button. Also if time taken to execute myFunc is more than 20 seconds then timer will stop it and display alert.

Below is my code :

import UIKit

class ViewController: UIViewController {

    var myTimer = NSTimer()
    var isSet = true
    var icount = 0

    let operationQueue = NSOperationQueue()


    override func viewDidLoad() {
        super.viewDidLoad()

    }

    var th123:NSThread!


    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }


    func myFunc()
    {
        println("Thread start..")
    }


    @IBAction func btnClickEvent(sender: AnyObject) {

       if(isSet == false)
        {
            isSet = true
            myTimer.invalidate()

            // th123.cancel()
            operationQueue.cancelAllOperations()

            btnClick.setTitle("Start", forState: UIControlState.Normal)
            //NSThread.exit()
        }
        else if (isSet == true)
        {
            isSet = false

            myTimer = NSTimer.scheduledTimerWithTimeInterval(2, target: self, selector: Selector("checkTime"), userInfo: nil, repeats: true)
            NSLog("Timer started..")
            btnClick.setTitle("Stop", forState: UIControlState.Normal)

            Other()

        }

    }

    func myfunc1()
    {

    }

    func checkTime()
    {
        icount = icount + 10

        if( icount > 18 ) {

            isSet = false

            operationQueue.cancelAllOperations()

            let alertController = UIAlertController(title: "iOScreator", message:
                "Opps Some Error occurred !!", preferredStyle: UIAlertControllerStyle.Alert)
            alertController.addAction(UIAlertAction(title: "Dismiss", style: UIAlertActionStyle.Default,handler: nil))

            self.presentViewController(alertController, animated: true, completion: nil)
            myTimer.invalidate()
            btnClick.setTitle("Start", forState: UIControlState.Normal)
        }

    }



 func Other() {

customOperation.completionBlock = {

    MyObject.myFunc()
}


var workerBlockOperation:NSBlockOperation = NSBlockOperation.self.init(
    block: {
        MyObject.myFunc()
    }
)


    operationQueue.addOperation(customOperation)
    operationQueue.addOperation(workerBlockOperation)


}


    @IBOutlet weak var lblstatus: UILabel!
    @IBOutlet weak var btnClick: UIButton!
}

MyObject.swift file

import Foundation

class MyObject {

  class func myFunc()
    {
        NSLog(" myFunc called ")

        for i in 1...1000000 {
            println(i)
        }
    }

}

I would prefer to go with NSThread but i'm don't know how to forcefully stop/kill the NSthread.

I added below code but still not able to cancel task


Solution

  • Cancelling NSOperation just sets it isCanceled property to true, it will not stop the execution of that operation, rest its up to you how you handle this, usually you will check for isCancelled before execution the code inside operation, something like this.

    if (!op.isCancelled){
    //its means operation (op) is not cancelled
    // execute cod
    }
    

    Update: If you are using NSBLock operation then it should be something like this

    customOpeation =  NSBlockOperation ()
            customOpeation .addExecutionBlock {
                if !customOpeation.cancelled
                {
                    // operation is not cancelled
                    // so you can execute code
                    myFunc()
                }
            }
    

    If you want to get check if operation is cancelled inside myFunc method, then you will need to have operation reference otherwise it will execute, and if you have reference you can do something like this.

    class MyObject {
    
      class func myFunc()
        {
            NSLog(" myFunc called ")
    
            for i in 1...1000000 {
                if operation.cancelled
                { //break loop as operation is cancelled
                }
                println(i)
            }
        }
    
    }
    

    How you will send reference of an operation to myFunc will depend how your app is architect.

    Recommended Subclass NSOperation and add functionality inside that than you can easily check if operation is cancelled or not and this one is the recommended way

     class Opeation : NSOperation
        {
            override func main() {
                if !cancelled
                {
                    myFunc()
                }
            }
            func myFunc()
            {
                for i in 1...1000000 {
                    if cancelled
                    {
                        break
                    }
                    println(i)
                }
            }
        }
    

    After this just create an object of Operation and add it to opeartionQueue