2011-12-05 64 views
31

我有一個回調方法,我開始工作,但我想知道如何將值傳遞給它。Objective-C回調處理程序

什麼我是這樣的:

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

} 


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

上述工程的代碼,但我想值傳遞給方法。這看起來如何?例如:

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

回答

112

我不完全確定你要在那裏做什麼 - 你的回調是一個塊......是故意的嗎?我希望你的方法是這個樣子:

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

如果回調的目的是執行上完成一些額外的代碼(當你調用該方法規定),那麼塊將是有益的。例如,你的方法是這樣的:

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

    if (successful) { 
     completionBlock(); 
    } 
} 

然後調用像這樣的方法:

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

調用這個方法將盡快使用戶登錄到該帳戶,然後爲完成,顯示餘額。這顯然是一個人爲的例子,但希望你明白。

如果這不是您想要的東西,那麼只需使用上面的方法簽名即可。


EDIT(使用successful變量A更好的例子):

更好的設計。將傳遞一個布爾回描述登錄如何去完成塊:

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

您還會看到,這次我們在調用它之前檢查參數completionBlock不是nil - 如果您想允許這種方法od使用而不使用完成塊。您可以使用此方法,像這樣:

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

更妙的是(!如果你能原諒的例子大片),如果它會是有益的用戶知道失敗的原因,返回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); 
    } 
} 

呼叫者就可以使在完成塊的使用NSError來決定如何進行(最有可能的,描述到什麼地方出了錯用戶)。這種模式稍微不常見(儘管完全有效);大多NSError S被間接指針在NSFileWrapper小號-initWithURL:options:error:方法返回,例如:

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

在登錄例子,但是,我們可能期待的登錄嘗試採取一定量的時間來完成(例如登錄到一個在線帳戶),所以使用完成處理程序來傳回錯誤是完全合理的。

+0

謝謝你,這幫了我。是的,這是故意的。 – Jesse

+2

我可能會設計它2塊:成功和失敗 – vikingosegundo

+1

@vikingosegundo:是的,很好的建議。儘管根據上下文,將該成功作爲「BOOL」返回可能更容易,或者可能通過指針間接傳遞「NSError」對象以確定登錄進行得如何。 – Stuart