Objective-Ccallback处理程序

我有一个callback方法,我开始工作,但我想知道如何传递值。

我有什么是这样的:

@interface DataAccessor : NSObject { void (^_completionHandler)(Account *someParameter); } - (void) signInAccount:(void(^)(Account *))handler; 

上面的代码工作,但我想传递值的方法。 这看起来如何? 就像是:

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

我不完全确定你要在那里做什么 – 你的callback是一个块…是故意的吗? 我希望你的方法看起来像这样:

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

如果你的callback的目的是在完成时执行一些额外的代码(当你调用方法时指定),那么一个块将是有用的。 例如,你的方法看起来像这样:

 - (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... }]; 

此方法调用会将用户login到帐户中,然后一旦完成,就会显示余额。 这显然是一个人为的例子,但希望你能明白这个想法。

如果这不是你想要的那种东西,那么就简单地使用一个像上面那样的方法签名。


编辑(一个更好的例子,使用successfulvariables):

一个更好的devise是在完成块中传递一个布尔值来描述login进行得如何:

 - (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 – 如果你想让这个方法在没有完成块的情况下使用,这很重要。 你可以像这样使用这个方法:

 [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. (NB `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来决定如何进行(最有可能向用户描述出了什么问题)。 这种模式稍微不太常见(尽pipe是完全有效的)。 大多数NSError是通过指针间接返回的,例如在NSFileWrapper -initWithURL:options:error: method:

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

然而,在login示例中,我们可能期望login尝试花费一些时间来完成(例如login到在线帐户),所以使用完成处理程序来传递错误是完全合理的。