In un ambiente guidato dagli eventi, come dovrebbe una funzione "annulla" interrompere tutti gli altri eventi?

2

Nella mia app iOS, le cose sono principalmente guidate da eventi.

  1. L'utente preme un pulsante
  2. L'app ascolta un dispositivo esterno da collegare al dispositivo iOS
  3. Una volta rilevato il dispositivo (connesso), viene effettuata una chiamata asincrona a un servizio Web (per verificare l'autenticità dell'utente)
  4. Il servizio web restituisce l'autenticità dell'utente (come un booleano)
  5. Viene chiamato un altro servizio Web asincrono per l'autenticità della fase 2
  6. Il risultato viene restituito

La mia domanda è: se fornisco all'utente una finestra di dialogo che dice "Attendere, elaborazione" e do loro un pulsante "Annulla", come dovrei (o come posso) abortire tutto ciò che sta accadendo?

Un modo per farlo è semplicemente avere un booleano chiamato "userDidCancelEverything" e ogni metodo guidato dagli eventi controlla se questo è vero. Questo sembra brutto però.

    
posta Rowan Freeman 28.02.2013 - 01:08
fonte

2 risposte

1

Il modo in cui implementate una funzione di annullamento dipenderà ovviamente dal modo in cui implementate gli eventi nella vostra app. Ad esempio, quando l'utente tocca il pulsante, l'azione risultante potrebbe aggiungere un numero di operazioni a una coda di operazioni seriali: la prima operazione attenderà il collegamento del dispositivo, il successivo chiamerà il servizio Web di autenticazione e così via. Se lo fai in questo modo, l'azione del pulsante Annulla chiamerà il metodo -cancelAllEvents della coda di operazioni per svuotare la coda e quindi reimposta lo stato relativo alle operazioni su uno stato noto. Sarebbe simile se utilizzi qualche altro schema: ferma e rimuovi tutti gli eventi in sospeso, quindi imposta l'app su uno stato noto.

    
risposta data 28.02.2013 - 01:20
fonte
1

Ho saputo, questa è una vecchia domanda, ma abbastanza interessante, e c'è una bella soluzione:

Supponiamo che tutte quelle funzioni fossero asincrone. Il modello asincrono è chiamato "Continuazione".

Una possibile implementazione di tale "continuazione" potrebbe utilizzare direttamente le code e i blocchi di invio, ad esempio:

dispatch(my_queue, ^{
    [self connectDeviceWithCompletion:^(id result){
        if (result) {
            [self authenticateWithCompletion:^(id result){
                 if (result) {
                     [self performTwoFactorAuthWithCompletion:^(id result) {
                         if (result) {
                              ...
                         }
                     }];
                 }
            }];
        }
    }];
});

Come puoi vedere, la "continuazione" con la spedizione e i blocchi si confonde rapidamente e non ho nemmeno aggiunto il controllo degli errori e la cancellazione.

Nota che cancellare un blocco che è stato messo in coda non è così facilmente possibile.

Una soluzione più comprensibile che supporti anche la gestione degli errori e la cancellazione può essere ottenuta utilizzando un concetto chiamato "Promise" (vedi wiki Futures e promesse ]. Le promesse sono molto popolari in JavaScript e in altre lingue, ma ci sono alcune librerie Objective-C che implementano Promises, vedi questa risposta: successo: / fallimento: blocchi vs completamento: blocco .

Utilizzando la RXPromise libreria si potrebbe scrivere:

RXPromise* finalResult = [self connectDevice]
.then(^(id result){
    // device successfully connected with result
    return [self authenticate];
}, nil)
.then(^id(id result){
    // authenticated successfully with result
    return [self performTwoFactorAuth];
}, nil)
.then(^id(id result){
    // successfully performed two-factor-authentication
    // do something 
    ...
}, nil)

[finalResult setTimeout:5*60]; // we cancel everything after 5 minutes

// Catch any error:
finalResult.then(nil, id(NSError* error){
    NSLog(@"Something went wrong, or user cancelled with error: %@", error);
});

self.finalResultPromise = finalResult;
...

In seguito:

Supponiamo che l'utente aspetti che un risultato si verifichi alla fine. Quando si ritorna indietro dalla vista corrente, ciò annulla tutte le operazioni asincrone:

- (void) viewDidDisappear:(BOOL)animated {
    // we are no longer interested in the result         
    [self.finalResultPromise cancel];
    self.finalResultPromise = nil;

    [super viewDidDisappear:animated];
}

Divulgazione: sono l'autore di RXPromsie;)

    
risposta data 03.03.2014 - 22:08
fonte