2015-06-12 24 views
6

BFTask è stato un bene per me, ma ho una lamentela: non ho ancora visto un esempio funzionante di come si dovrebbe fare un compito cancel. L'insieme della documentazione sull'argomento si trova su their GitHub page con una singola sezione bassa che include tutto tranne la parte che mi interessa: come per annullare l'attività.Implementazione di attività che possono essere annullate in Bolts Framework (BFTask)

// Somewhere else. 
MYCancellationToken *cancellationToken = [[MYCancellationToken alloc] init]; 
[obj doSomethingComplicatedAsync:cancellationToken]; 

// When you get bored... 
[cancellationToken cancel]; 

loro frammento di codice è seguito da:

Nota: L'annullamento di token attuazione dovrebbe essere thread-safe.

Mi chiedo quanto segue:

  1. C'è una buona ragione che essi non possono aver fornito il metodo cancel sull'interfaccia BFTask stessa? Hanno una proprietà che rappresenta se l'attività è stata annullata, ma non c'è modo di annullarla.
  2. C'è una buona ragione che non includano una proprietà cancellationToken(s) nello stesso BFTask?
  3. L'implementazione di cancel è strettamente correlata all'attività stessa? O è possibile un'implementazione generale come nel caso di cancelAllOperations di un NSOperationQueue?

risposta

6
  1. Come sapete, BFTask è un'implementazione del Future and Promises costrutto:
    "un futuro è una vista segnaposto di sola lettura di una variabile, mentre una promessa è una scrivibile, contenitore unico incarico che imposta il valore del futuro ".
    Fondamentalmente, uno BFTask è un Future: è una vista segnaposto di sola lettura di una variabile.
    A BFTaskCompletionSource è una promessa: è un contenitore scrivibile, a assegnazione singola che definisce il valore del futuro. (o un errore - o annulla l'attività)
    L'interfaccia pubblica BFTask rimane di sola lettura, quindi non consente di annullarla direttamente.
  2. Ha la stessa risposta della domanda precedente: BFTask è di sola lettura e rappresenta un valore di sola lettura. L'esposizione di token di cancellazione ti consentirebbe di manipolare il compito, che è in contraddizione con la sua natura.
  3. Diamo un'occhiata: https://github.com/BoltsFramework/Bolts-iOS/blob/master/Bolts/Common/BFCancellationToken.m Il token BFCancellationToken memorizza solo uno stato, che può essere verificato da BFTask. Il tuo codice attività asincrona può fondamentalmente verificare regolarmente che cancellationRequested sia impostato su true, che ti consente di annullare manualmente l'attività.

    Nota: il quadro Bulloni iOS docs dice: "Un'attività è un po 'come una Promessa JavaScript" che può essere fonte di confusione, perché è davvero un futuro. Penso che sia stato appena nominato sbagliato nelle sue origini Javascript.
2

Usa [self.bfTaskCancelationToken cancel]; codice per annullare serie BFTask

// --------- Registrati BFCancellationTokenSource -------------------- -------

self.bfTaskCancelationToken = [BFCancellationTokenSource cancellationTokenSource]; 
     [self.bfTaskCancelationToken.token registerCancellationObserverWithBlock:^{ 

      NSLog(@"task hasbeen Cancelled....."); 
      //Do stuff on cancelation task 

    } ]; 

// ---------------- Implemente Serie BFTask --------------- ---------------------------

Nota: c'è cancellationToken:self.bfTaskCancelationToken.token codice dopo [task continueWithBlock:^id(BFTask *task)

[[[self showAlertProgressHud] continueWithBlock:^id(BFTask *taskLog) { 


      BFTask *task = [BFTask taskWithResult:nil]; 
      for (int i=0; i<self.arrAssetPhotos.count; i++) { 

       AIAssetPhoto *assetPhoto = self.arrAssetPhotos[i]; 
       task = [task continueWithBlock:^id(BFTask *task) { 
        // Return a task that will be marked as completed. 
        return [self processOnAssetPhoto:assetPhoto index:i completion:NULL]; 
       } cancellationToken:self.bfTaskCancelationToken.token]; 

      } 

      return task; 


     }] continueWithBlock:^id(BFTask *task) { 

      // all asset photos process are done. 
      return nil; 
     }]; 

// --------- Come annullare BFtask continuo? -------------------

// just by calling one simple method 
    [self.bfTaskCancelationToken cancel]; 
4

C'è abbastanza utile implementazione di token cancellazione di bulloni, ma per qualche motivo non è documentato affatto fuori dei file di intestazione. La chiave è l'uso di BFCancellationTokenSource. È necessario mantenere un riferimento allo BFCancellationTokenSource per emettere e annullare uno BFCancellationToken.

Nel mio esempio ho una particolare funzione chiamata cancellableFunction() che emette una serie di attività in successione. Se la funzione viene richiamata nuovamente prima dell'ultima chiamata, voglio che le attività non completate della chiamata precedente vengano annullate.

La chiave qui è di passare lo token in ciascuna chiamata di funzione continueWith. Se in qualsiasi momento lo token viene cancellato tramite lo tokenSource, i numeri di telefono non corretti successBlock non verranno eseguiti. Puoi anche controllare lo stato di cancellazione tramite task.cancelled in ogni BFContinuationBlock (ovviamente sarà falso nei blocchi di successo).

Ecco un esempio:

class ViewController: UIViewController { 

    ... 

    // instance reference to tokenSource so that it can be cancelled by any function in the ViewController 
    var tokenSource: BFCancellationTokenSource? 

    ... 

    func cancellableFunction() -> BFTask { 

     // First cancel the previous token 
     tokenSource?.cancel() 
     // Replace the previous TokenSource with a new one 
     tokenSource = BFCancellationTokenSource() 
     // Issue new Token from the new TokenSource 
     let token = tokenSource!.token 

     return functionThatReturnsBFTask().continueWithSuccessBlock({ (task:BFTask) -> AnyObject? in 

     ... 

     return nil 
     }, cancellationToken: token).continueWithExecutor(BFExecutor.mainThreadExecutor(), successBlock: { (task:BFTask) -> AnyObject? in 

     ... 

     return nil 
     }, cancellationToken: token).continueWithBlock({ (task:BFTask) -> AnyObject? in 

     // Here you can perform an actions you want to take on cancellation 
     if task.cancelled { 

     } 

     ... 

     return nil 
     }, cancellationToken: token) 
    } 

    ... 

}