2011-12-05 41 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