ios Objective-C 回调处理程序
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/8393138/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Objective-C callback handler
提问by Jesse
I have a callback method that I got to work, but I want to know how to pass values to it.
我有一个可以工作的回调方法,但我想知道如何将值传递给它。
What I have is this:
我有的是这个:
@interface DataAccessor : NSObject
{
void (^_completionHandler)(Account *someParameter);
}
- (void) signInAccount:(void(^)(Account *))handler;
The code above works, but I want to pass values to the method. How would this look? Something like:
上面的代码有效,但我想将值传递给该方法。这看起来如何?就像是:
- (void) signInAccount:(void(^)(Account *))handler user:(NSString *) userName pass:(NSString *) passWord;
?
?
回答by Stuart
I'm not entirely sure what you're trying to do there - your callback is a block... is that intentional? I would expect your method to look something like this:
我不完全确定你想在那里做什么 - 你的回调是一个块......这是故意的吗?我希望你的方法看起来像这样:
- (void)signInAccountWithUserName:(NSString *)userName password:(NSString *)password;
If the intention of your callback is to execute some additional code (specified when you call the method) on completion, then a block would be useful. For example, your method would look like this:
如果回调的目的是在完成时执行一些额外的代码(在调用方法时指定),那么块会很有用。例如,您的方法如下所示:
- (void)signInAccountWithUserName:(NSString *)userName
password:(NSString *)password
completion:(void (^)(void))completionBlock
{
// ...
// Log into the account with `userName` and `password`...
//
if (successful) {
completionBlock();
}
}
And then call the method like so:
然后像这样调用方法:
[self signInAccountWithUserName:@"Bob"
password:@"BobsPassword"
completion:^{
[self displayBalance]; // For example...
}];
This method call would log the user into the account and then as soon as that is complete, show the balance. This is clearly a contrived example, but hopefully you get the idea.
此方法调用会将用户登录到帐户,然后在完成后立即显示余额。这显然是一个人为的例子,但希望你能明白。
If this is not the kind of thing you intended, then simply use a method signature like the one above.
如果这不是您想要的类型,那么只需使用像上面那样的方法签名。
EDIT (A better example using the successful
variable):
编辑(使用successful
变量的一个更好的例子):
A better design would be to pass a Boolean back in the completion block that describes how well the login went:
更好的设计是在完成块中传递一个布尔值来描述登录的进展情况:
- (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);
}
You'll also see that this time around we're checking that the completionBlock
parameter is not nil
before calling it - this is important if you want to allow the method to be used withouta completion block. You might use this method like so:
您还将看到,这一次我们在调用之前检查completionBlock
参数是否不在nil
- 如果您希望允许在没有完成块的情况下使用该方法,这一点很重要。你可以像这样使用这个方法:
[self signInAccountWithUserName:@"Bob"
password:@"BobsPassword"
completion:^(BOOL success) {
if (success) {
[self displayBalance];
} else {
// Could not log in. Display alert to user.
}
}];
Better still (if you can excuse the swaths of examples!), if it would be useful for the user to know the reason for the failure, return an NSError
object:
更好的是(如果你能原谅大量的例子!),如果用户知道失败的原因是有用的,返回一个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);
}
}
The caller can then make use of the NSError
in the completion block to decide how to proceed (most likely, to describe to the user what went wrong). This kind of pattern is slightly less common (though perfectly valid); mostly NSError
s are returned by pointer indirection, for example in the NSFileWrapper
s -initWithURL:options:error:
method:
然后调用者可以使用NSError
完成块中的 来决定如何继续(最有可能的是向用户描述出了什么问题)。这种模式不太常见(虽然完全有效);大多数NSError
s 由指针间接返回,例如在NSFileWrapper
s-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).
In the login example, however, we are probably expecting the login attempt to take some amount of time to complete (for example logging into an online account), so it is perfectly reasonable to make use of a completion handler that passes an error back.
然而,在登录示例中,我们可能期望登录尝试需要一些时间才能完成(例如登录在线帐户),因此使用将错误传回的完成处理程序是完全合理的。