2017-08-07 37 views
2

我正在創建一個UIView,它在UIViewController中運行許多異步任務。在某些時候,我希望能夠刪除UIView並停止所有正在運行的任務。但是,調用removeFromSuperview()不會停止任務。有沒有辦法可以做到這一點?停止UIView中的所有異步任務

示例代碼

class ViewController: UIViewController { 

    let v = SomeView() 

    override func viewDidLoad() { 
     super.viewDidLoad() 

     v.frame = CGRect(x: 0, y: 0, width: 10, height: 10) 
     self.view.addSubview(v) 

     let v1 = UIButton() 
     v1.frame = CGRect(x: 0, y: 0, width: 100, height: 100) 
     v1.backgroundColor = UIColor.blue 
     v1.addTarget(self, action: #selector(removeV(_:)), for: .touchUpInside) 
     self.view.addSubview(v1) 
    } 

    func removeV(_ sender: UIButton) { 
     print("V REMOVED") 
     v.removeFromSuperview() 
    } 
} 

class SomeView: UIView { 
    override func draw(_ rect: CGRect) { 
     DispatchQueue.global().async { 
      var c = 0 
      while true { 
       print(String(c) + " DOING SOME TASK") 
       c += 1 
       sleep(1) 
      } 
     } 
    } 
} 

示例記錄

0 DOING SOME TASK 
1 DOING SOME TASK 
V REMOVED 
2 DOING SOME TASK 
3 DOING SOME TASK 
4 DOING SOME TASK 
... 
+0

這是一個例子來說明一些任務正在發生很長一段時間。當我刪除視圖時,我希望所有這些任務都停止。 –

回答

3

有一種辦法取消使用DispatchWorkItem在DispatchQueue塊。例如。

//create the dispatch work item 
var dwi2:DispatchWorkItem? 
dwi2 = DispatchWorkItem { 
    var c = 0 
    while true { 
     print(String(c) + " DOING SOME TASK") 
     c += 1 
     sleep(1) 
     if (dwi2?.isCancelled)!{ 
      break 
     } 
    } 
} 

//submit the work item to the default global queue 
DispatchQueue.global().async(execute: dwi2!) 

//cancelling the task after 3 seconds 
DispatchQueue.global().async{ 
    sleep(3) 
    dwi2?.cancel() 
} 

你必須檢查你的工作塊內的isCancelled物業停止進一步執行。

請參考this寫得很好的文章瞭解更多詳情。

0

可以存儲與您SomeView實例中的任務隊列。檢查documentation欲知更多信息。

提示:您可以添加儘可能多的操作,因爲你需要,然後去除

2

-cancelAllOperations總之你不能停止GCD任務。

要增加能力管理後臺任務,你應該使用OperationOperationQueue 簡單的例子:

class YourOperation: Operation { 

    func execute() { 
     // Execute your async task here. 

     // call finish() if success finished tasks 
     // call cancel() if some error 
    } 
} 


let queue = OperationQueue() 
let yourOperation = YourOperation() 
queue.addOperation(yourOperation) 

// to stop single operation 
yourOperation.cancel() 



// to stop all operations 
queue.cancelAllOperations() 
+0

哦,我明白了,我無法讓整個'UIView'成爲'Operation'嗎? –

+0

我不明白你爲什麼需要這個,你不能在後臺線程中更改UI –

+2

@VadimKozak我不認爲這就是Anters在他的評論中所說的。我相信他的意思是說,如果他可以用Operation Class對UIView進行子類化併爲其視圖調用默認的cancelAllOperations,那麼答案就不會是這樣。 – NSNoob

0

你不需要像其他人提到的那樣用NSOperations使你的生活複雜化。您可以持有一個標誌(而不是while true - >while flag),並在您希望任務退出時將其設置爲false。這樣您就可以在任何時候退出並完全控制流量和可能的錯誤。另外,爲了使事情更健壯,可以在該標誌讀取之前使用無鎖內存屏障(因爲您將從不同線程讀取/寫入它)。這樣你將避免CPU緩存和內存W/R訂單優化問題。

+0

嘿,謝謝你的輸入。我實際上並沒有運行一段時間的真正循環,它只是結構的一個例子。我有很多任務發生在很長一段時間,他們實際上是動態生成的,所以我沒有跟蹤每個人的所有條件等...我基本上需要在用戶退出視圖控制器時終止整個視圖 –