2016-07-14 23 views
13

Attualmente sto giocando con Grand Central Dispatch e ho scoperto una classe chiamata DispatchWorkItem. La documentazione sembra un po 'incompleta quindi non sono sicuro di usarlo nel modo giusto. Ho creato il seguente frammento e mi aspettavo qualcosa di diverso. Mi aspettavo che l'oggetto fosse cancellato dopo aver chiamato cancel su di esso. Ma l'iterazione continua per qualche motivo. Qualche idea su cosa sto facendo male? Il codice sembra a posto per me.Come fermare un DispatchWorkItem in GCD?

@IBAction func testDispatchItems() { 
    let queue = DispatchQueue.global(attributes:.qosUserInitiated) 
    let item = DispatchWorkItem { [weak self] in 
     for i in 0...10000000 { 
      print(i) 
      self?.heavyWork() 
     } 
    } 

    queue.async(execute: item) 
    queue.after(walltime: .now() + 2) { 
     item.cancel() 
    } 
} 

risposta

28

GCD non esegue le cancellazioni preventive. Quindi, per interrompere un oggetto di lavoro che è già stato avviato, è necessario verificare personalmente le cancellazioni. È possibile utilizzare isCancelled (precedentemente noto come dispatch_block_testcancel).

func testDispatchItems() { 
    let queue = DispatchQueue.global() 

    var item: DispatchWorkItem! 

    // create work item 

    item = DispatchWorkItem { [weak self] in 
     for i in 0 ... 10_000_000 { 
      if item.isCancelled { break } 
      print(i) 
      self?.heavyWork() 
     } 
     item = nil // resolve strong reference cycle 
    } 

    // start it 

    queue.async(execute: item) 

    // after five seconds, stop it if it hasn't already 

    queue.asyncAfter(deadline: .now() + 5) { [weak item] in 
     item?.cancel() 
    } 
} 
+0

Grazie, è esattamente quello che stavo cercando. –

+0

È possibile riutilizzare DispatchWorkItem dopo l'annullamento? – pixelfreak

+0

@pixelfreak - No. Creane uno nuovo se vuoi ricominciare. – Rob

0

Non esiste un'API asincrona in cui la chiamata di un metodo "Annulla" annulla un'operazione in esecuzione. In ogni singolo caso, un metodo "Annulla" farà qualcosa in modo che l'operazione possa scoprire se è stato cancellato, e l'operazione deve controllarlo di volta in volta e poi smettere di fare più lavoro da solo.

non so l'API in questione, ma in genere sarebbe qualcosa di simile

 for i in 0...10000000 { 
      if (self?.cancelled) 
       break; 

      print(i) 
      self?.heavyWork() 
     }