【问题标题】:Objective-C callback handler [closed]Objective-C 回调处理程序 [关闭]
【发布时间】:2012-01-13 15:43:32
【问题描述】:

我有一个需要工作的回调方法,但我想知道如何将值传递给它。

我拥有的是这样的:

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

}


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

上面的代码有效,但我想将值传递给方法。这看起来如何?比如:

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

?

【问题讨论】:

    标签: objective-c ios methods callback objective-c-blocks


    【解决方案1】:

    我不完全确定你想在那里做什么 - 你的回调是一个块......这是故意的吗?我希望您的方法看起来像这样:

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

    此方法调用会将用户登录到帐户,然后在完成后立即显示余额。这显然是一个人为的例子,但希望你能明白。

    如果这不是您想要的,那么只需使用上述方法签名即可。


    编辑(使用successful 变量的更好示例):

    更好的设计是在完成块中传递一个布尔值,用于描述登录的情况:

    - (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 - 如果您希望允许在不使用该方法的情况下使用该方法,这一点很重要 em> 一个完成块。你可以像这样使用这个方法:

    [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 来决定如何继续(很可能是向用户描述出了什么问题)。这种模式不太常见(尽管完全有效);大多数NSErrors 是通过指针间接返回的,例如在NSFileWrappers -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).
    

    然而,在登录示例中,我们可能预计登录尝试需要一些时间才能完成(例如登录到在线帐户),因此使用传递一个完成处理程序是完全合理的错误返回。

    【讨论】:

    • @vikingosegundo:是的,很好的建议。虽然,根据上下文,将成功返回为BOOL 可能更容易,或者可能通过指针间接传递NSError 对象以确定登录的顺利程度。
    • 有人能解释一下if (successful) 部分的内容吗?如何定义successful?我猜是BOOL?
    • @pigeonfactory:在上面的例子中,successful 只是一个假定的局部变量,返回来描述登录是否有效。更好的解决方案可能是在完成块中返回该布尔值。我已经对说明这一点的答案添加了一个编辑。
    • @Stuart 你会做类似完成处理程序stackoverflow.com/questions/49857236/…
    • Swift func myFunction(str: String, completionHandler: @escaping (String) -> ()){ completionHandler("") } myFunction(str: "someThing", completionHandler: {(str) in })
    猜你喜欢
    • 1970-01-01
    • 2014-09-20
    • 2016-06-25
    • 1970-01-01
    • 2012-11-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多