2011-12-05 15 views
31

Mam metodę zwrotną, że mam do pracy, ale chcę wiedzieć, jak przekazać wartości do niego.Objectback-C handler oddzwonienia

Co mam to:

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

} 


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

Powyższy kod działa, ale chcę przekazać wartości do metody. Jak by to wyglądało? Coś takiego:

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

?

Odpowiedz

112

Nie jestem do końca pewien, co próbujesz tam zrobić - twoje wywołanie zwrotne jest blokiem ... czy to zamierzone? Spodziewam się metoda wyglądać mniej więcej tak:

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

Jeśli intencją swojej zwrotnego ma wykonać jakiś dodatkowy kod (podany podczas wywołania metody) po zakończeniu, a następnie blok byłby przydatny. Na przykład, metoda będzie wyglądać następująco:

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

    if (successful) { 
     completionBlock(); 
    } 
} 

a następnie wywołać metodę tak:

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

To wywołanie metody będzie najszybciej zalogować użytkownika na konto, a następnie jako że jest kompletna , pokaż saldo. Jest to wyraźnie wymyślny przykład, ale mam nadzieję, że wpadniesz na ten pomysł.

Jeśli nie jest to coś, co zamierzałeś, po prostu użyj sygnatury metody podobnej do powyższej.


EDIT (Lepszym przykładem użyciu zmiennej successful):

Lepszy projekt będzie zdać Boolean powrotem w bloku realizacji, który opisuje, jak dobrze logowanie poszedł:

- (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); 
} 

Zobaczysz również, że tym razem sprawdzamy, czy parametr completionBlock nie jest nil przed wywołaniem - jest to ważne, jeśli chcesz zezwolić od do użycia bez bloku zakończenia. Można użyć tej metody tak:

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

Jeszcze lepiej (! czy można wybaczyć te połacie przykładach), jeśli byłoby użyteczne dla użytkownika, aby poznać przyczynę niepowodzenia, zwraca obiekt 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); 
    } 
} 

dzwoniący może wtedy skorzystać z NSError w bloku zakończenia zdecydować, jak postępować (najprawdopodobniej, do opisania dla użytkownika, co poszło źle).Ten rodzaj wzoru jest nieco mniej powszechny (choć całkowicie poprawny); głównie NSError s są zwracane przez wskaźnik pośredni, na przykład w NSFileWrapper s -initWithURL:options:error: metody:

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). 

W przykładzie logowania, jednakże jesteśmy prawdopodobnie spodziewa próbę logowania do podjęcia pewnej ilości czasu, aby zakończyć (na przykład logowanie do konta online), więc całkowicie uzasadnione jest korzystanie z procedury obsługi zakończeń, która przekazuje błąd z powrotem.

+0

Dziękuję, pomogło mi to. Tak, jest celowe. – Jesse

+2

Prawdopodobnie zaprojektowałbym to z 2 blokami: sukces i porażka – vikingosegundo

+1

@vikingosegundo: Tak, dobra sugestia. Chociaż, w zależności od kontekstu, może być łatwiej zwrócić ten sukces jako 'BOOL' lub ewentualnie przekazać obiekt' NSError' za pomocą indeksu-pośrednictwa, aby określić, jak dobrze przebiegło logowanie. – Stuart