У меня есть ErrorBlock (errorBlock), определенный в моем коде, который можно вызывать несколько раз. Хотя я хочу, чтобы меня проинформировали только один раз, поэтому моя идея заключалась в том, чтобы обернуть мой ErrorBlock (errorBlock) внутри другого (pErrorBlock) и установить для него значение nil.

Теперь я хотел иметь метод очистки, который устанавливает ссылки на innerBlock равными нулю. Но когда я передаю внутренний блок методу очистки (тест 1), я получаю другой результат, чем когда я устанавливаю внутренний блок ErrorBlock nil self (тест 2).

Как я могу получить результат теста 2 с (немного измененным) кодом теста 1?

Мой первый тест, обувь результат, который я не понимаю:

-(void)testBlocks{
    __block ErrorBlock pErrorBlock= ^(void){
        NSLog(@"Foo");
    };
    NSLog(@"test: %p",pErrorBlock);

    ErrorBlock errorBlock = ^(void){
        dispatch_async(dispatch_get_main_queue(), ^{
            if(pErrorBlock){
                NSLog(@"call: %p",pErrorBlock);
                pErrorBlock();
            }

            [self cleanupErrorBlockWith:pErrorBlock];
        });
    };

    errorBlock();
    errorBlock();
}

- (void) cleanupErrorBlockWith:(ErrorBlock)errorBlock{

    NSLog(@"cleanup: %p",errorBlock);
    errorBlock = nil;
    NSLog(@"after cleanup: %p",errorBlock);
}

Результат:

2013-02-08 16:39:04.484 Tests[9501:907] test: 0x3a6ba8
2013-02-08 16:39:04.496 Tests[9501:907] call: 0x3a6ba8
2013-02-08 16:39:04.497 Tests[9501:907] Foo
2013-02-08 16:39:04.498 Tests[9501:907] cleanup: 0x3a6ba8
2013-02-08 16:39:04.499 Tests[9501:907] after cleanup: 0x0
2013-02-08 16:39:04.500 Tests[9501:907] call: 0x3a6ba8
2013-02-08 16:39:04.501 Tests[9501:907] Foo
2013-02-08 16:39:04.502 Tests[9501:907] cleanup: 0x3a6ba8
2013-02-08 16:39:04.503 Tests[9501:907] after cleanup: 0x0

Мой второй тест с желаемым результатом:

-(void)testBlocks{
    __block ErrorBlock pErrorBlock= ^(void){
        NSLog(@"Foo");
    };
    NSLog(@"test: %p",pErrorBlock);

    ErrorBlock errorBlock = ^(void){
        dispatch_async(dispatch_get_main_queue(), ^{
            if(pErrorBlock){
                NSLog(@"call: %p",pErrorBlock);
                pErrorBlock();
                NSLog(@"cleanup: %p",pErrorBlock);
                pErrorBlock = nil;
                NSLog(@"after cleanup: %p",pErrorBlock);
            }
        });
    };

    errorBlock();
    errorBlock();
}

Результат:

2013-02-08 16:42:18.485 Tests[9540:907] test: 0x3a6ba8
2013-02-08 16:42:18.496 Tests[9540:907] call: 0x3a6ba8
2013-02-08 16:42:18.498 Tests[9540:907] Foo
2013-02-08 16:42:18.499 Tests[9540:907] cleanup: 0x3a6ba8
2013-02-08 16:42:18.500 Tests[9540:907] after cleanup: 0x0
2
Jakob 8 Фев 2013 в 19:54
1
Конечно, errorBlock = nil; не имеет никакого эффекта, учитывая, что он передан как параметр ...
 – 
trojanfoe
8 Фев 2013 в 20:07

1 ответ

Лучший ответ

Вы передаете блок по значению, передайте его по ссылке следующим образом. Также перемещаем ваш вызов cleanupErrorBlockWith: внутри оператора if.

-(void)testBlocks{
    __block ErrorBlock pErrorBlock= ^(void){
        NSLog(@"Foo");
    };
    NSLog(@"test: %p",pErrorBlock);

    ErrorBlock errorBlock = ^(void){
        dispatch_async(dispatch_get_main_queue(), ^{
            if(pErrorBlock){
                NSLog(@"call: %p",pErrorBlock);
                pErrorBlock();
                [self cleanupErrorBlockWith:&pErrorBlock];
            }
        });
    };

    errorBlock();
    errorBlock();
}


- (void) cleanupErrorBlockWith:(ErrorBlock*)errorBlock{
    NSLog(@"cleanup: %p",*errorBlock);
    *errorBlock = nil;
    NSLog(@"after cleanup: %p",*errorBlock);
}
2
Inder Kumar Rathore 8 Фев 2013 в 20:11
Хорошо .. Если бы вы дали определение ErrorBlock, я бы ответил на ваш вопрос на 5 минут раньше. : D В любом случае +1 за ваш вопрос, так как он проясняет мою концепцию создания блочных переменных :)
 – 
Inder Kumar Rathore
8 Фев 2013 в 20:14
Вызов nil должен быть разрешен. вот почему я бы предпочел, чтобы это было снаружи, если. причина в том, что мой настоящий метод очистки принимает несколько аргументов блока, и я не хочу проверять nil для всех из них.
 – 
Jakob
8 Фев 2013 в 20:18
Да, вы можете иметь это снаружи, если. но в этом нет смысла;), так как он присвоит ноль указателю, который уже равен нулю o_O
 – 
Inder Kumar Rathore
8 Фев 2013 в 20:24