Подтвердить что ты не робот

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;

?

4b9b3361

Ответ 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...
                     }];

Этот вызов метода будет регистрировать пользователя в учетной записи, а затем, как только это будет завершено, покажите баланс. Это явно надуманный пример, но, надеюсь, вы получите эту идею.

Если это не та вещь, которую вы намеревались, просто используйте сигнатуру метода, подобную приведенной выше.


EDIT (лучший пример с использованием переменной 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 - это важно, если вы хотите разрешить использование метода без блока завершения. Вы можете использовать этот метод следующим образом:

[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 возвращаются указателем-указателем, например, в методе 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).

Однако в примере для входа мы, вероятно, ожидаем, что попытка входа в систему займет некоторое время (например, войти в онлайн-учетную запись), поэтому вполне разумно использовать обработчик завершения, который передает ошибка назад.