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到帐户中,然后一旦完成,就会显示余额。 这显然是一个人为的例子,但希望你能明白这个想法。
如果这不是你想要的那种东西,那么就简单地使用一个像上面那样的方法签名。
编辑(一个更好的例子,使用successful
variables):
一个更好的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到在线帐户),所以使用完成处理程序来传递错误是完全合理的。