2011-12-05 11 views
31

Ho un metodo di callback che ho avuto modo di lavorare, ma voglio sapere come passare valori ad esso.Gestore di callback Objective-C

Quello che ho è questa:

@interface DataAccessor : NSObject 
{ 
    void (^_completionHandler)(Account *someParameter); 

} 


- (void) signInAccount:(void(^)(Account *))handler; 

Il codice sopra funziona, ma voglio passare i valori al metodo. Come sarebbe questo? Qualcosa di simile:

- (void) signInAccount:(void(^)(Account *))handler user:(NSString *) userName pass:(NSString *) passWord; 

?

risposta

112

Non sono del tutto sicuro di cosa stai provando a fare lì - la tua richiamata è un blocco ... è intenzionale? Mi aspetterei il metodo a guardare qualcosa di simile:

- (void)signInAccountWithUserName:(NSString *)userName password:(NSString *)password; 

Se l'intenzione del callback è quello di eseguire del codice aggiuntivo (specificato quando si chiama il metodo) al termine, poi un blocco sarebbe utile. Ad esempio, il metodo sarebbe simile a questa:

- (void)signInAccountWithUserName:(NSString *)userName 
         password:(NSString *)password 
         completion:(void (^)(void))completionBlock 
{ 
    // ... 
    // Log into the account with `userName` and `password`... 
    // 

    if (successful) { 
     completionBlock(); 
    } 
} 

E quindi chiamare il metodo in questo modo:

[self signInAccountWithUserName:@"Bob" 
         password:@"BobsPassword" 
        completion:^{ 
         [self displayBalance]; // For example... 
        }]; 

Questa chiamata metodo potrebbe accedere l'utente sul conto e poi, non appena che è completo , mostra il saldo. Questo è chiaramente un esempio forzato, ma spero che tu abbia l'idea.

Se questo non è il tipo di cosa che si intendeva, quindi utilizzare semplicemente una firma del metodo come quella sopra.


EDIT (Un esempio migliore utilizzando la variabile successful):

Un design migliore sarebbe quella di passare un valore booleano indietro nel blocco di completamento che descrive quanto bene il login è andato:

- (void)signInAccountWithUserName:(NSString *)userName 
         password:(NSString *)password 
         completion:(void (^)(BOOL success))completionBlock 
{ 
    // Log into the account with `userName` and `password`... 
    // BOOL loginSuccessful = [LoginManager contrivedLoginMethod]; 

    // Notice that we are passing a BOOL back to the completion block. 
    if (completionBlock != nil) completionBlock(loginSuccessful); 
} 

Vedrai anche che questa volta stiamo controllando che il parametro completionBlock non sia nil prima di chiamarlo, questo è importante se vuoi consentire il meth da utilizzare senza un blocco di completamento. Si potrebbe utilizzare questo metodo in questo modo:

[self signInAccountWithUserName:@"Bob" 
         password:@"BobsPassword" 
        completion:^(BOOL success) { 
         if (success) { 
          [self displayBalance]; 
         } else { 
          // Could not log in. Display alert to user. 
         } 
        }]; 

Meglio ancora (! Se si può scusare le distese di esempi), se sarebbe utile per l'utente di conoscere la ragione del fallimento, restituire un oggetto NSError:

- (void)signInAccountWithUserName:(NSString *)userName 
         password:(NSString *)password 
         completion:(void (^)(NSError *error))completionBlock 
{ 
    // Attempt to log into the account with `userName` and `password`... 

    if (loginSuccessful) { 
     // Login went ok. Call the completion block with no error object. 
     if (completionBlock != nil) completionBlock(nil); 
    } else { 
     // Create an error object. (N.B. `userInfo` can contain lots of handy 
     // things! Check out the NSError Class Reference for details...) 
     NSInteger errorCode; 
     if (passwordIncorrect) { 
      errorCode = kPasswordIncorrectErrorCode; 
     } else { 
      errorCode = kUnknownErrorCode; 
     } 
     NSError *error = [NSError errorWithDomain:MyLoginErrorDomain code:errorCode userInfo:nil]; 
     if (completionBlock != nil) completionBlock(error); 
    } 
} 

il chiamante può quindi utilizzare il NSError nel blocco di completamento per decidere come procedere (molto probabilmente, per descrivere all'utente cosa è andato storto).Questo tipo di schema è leggermente meno comune (sebbene perfettamente valido); per lo più NSError s vengono restituiti dal puntatore indiretto, per esempio nel NSFileWrapper s -initWithURL:options:error: metodo:

NSError *error; 
NSFileWrapper *fw = [[NSFileWrapper alloc] initWithURL:url options:0 error:&error]; 
// After the above method has been called, `error` is either `nil` (if all went well), 
// or non-`nil` (if something went wrong). 

Nell'esempio di accesso, però, stiamo probabilmente aspettavamo il tentativo di accesso a prendere una certa quantità di tempo per completare (per esempio accedere a un account online), quindi è perfettamente ragionevole utilizzare un gestore di completamento che restituisce un errore.

+0

Grazie, questo mi ha aiutato. Sì, è intenzionale. – Jesse

+2

Probabilmente lo progetterei con 2 blocchi: successo e fallimento – vikingosegundo

+1

@vikingosegundo: Sì, buon suggerimento. Sebbene, a seconda del contesto, potrebbe essere più facile restituire tale successo come 'BOOL', o eventualmente passare in un oggetto' NSError' da pointer-indirection per determinare quanto bene è andato l'accesso. – Stuart

Problemi correlati